Beruflich Dokumente
Kultur Dokumente
Jedan od najvanijih, ali uprkos tome esto slabo shvaenih delova programskog jezika
kao to je JavaScript jeste kako izraziti ponaanje programa koje je promenljivo tokom
vremena.
To se ne svodi samo na pitanje ta se dogaa od poetka petlje for do kraja petlje for,
kojoj je, razume se, potrebno izvesno vreme (vie mikrosekundi ili milisekundi) da bi se
izvrila. To je pitanje ta se dogaa kada se deo programa izvrava sada, a neki njegov
drugi deo se izvrava kasnije tokom perioda izmeu sada i kasnije, kada program za-
pravo nije aktivan.
Praktino svaki netrivijalan program koji je dosad napisan (naroito na JS-u) morao
je da na jedan ili drugi nain upravlja tim intervalom, bez obzira na to da li eka dok ko-
risnik unosi ulazne podatke, ili eka podatke iz baze podataka ili sistema datoteka, alje
podatke kroz mreu i eka odziv iz nje, ili obavlja posao koji se ponavlja u jednakim vre-
menskim intervalima (kao to je animacija). U svim tim razliitim sluajevima, program
mora da upravlja svojim stanjem kroz periode neaktivnosti. Kao to kae poznata pre-
poruka iz londonskog metroa (u vezi s rastojanjem izmeu vrata vagona i ivice perona):
vodite rauna o razmaku.
U stvari, taj odnos izmeu sada i kasnije delova programa ini sr asinhronog
programiranja.
Nesporno je da mogunost asinhronog programiranja postoji jo od samih poetaka
JavaScripta. Ipak, veina JS programera nije nikad zaista paljivo razmatrala kako i gde
se ono pojavljuje u njihovim programima, niti istraivala razne druge naine da ga pri-
meni. Dovoljno dobro reenje uvek je bila skromna povratna funkcija. Mnogi i danas tvr-
de da su povratne funkcije vie nego dovoljne.
Ali kako JS nastavlja da raste i iri se i po obimu i po sloenosti kako bi zadovoljio
neprekidno rastue zahteve za prvoklasnim jezikom koji radi i u itaima veba, i na ser-
verima i na svakom zamislivom ureaju izmeu njih, napori koje ulaemo da bismo
upravljali asinhronizmom softvera postaju sve tei i zahtevaju nalaenje reenja koja su
istovremeno i razumnija i pruaju vie mogunosti.
Mada vam sve ovo moda zasad izgleda prilino apstraktno, znajte da emo se time
baviti detaljnije i konkretnije u celom ovom delu knjige. U narednih nekoliko poglav-
lja prouiemo vie novih tehnika koje tek poinju da se primenjuju za asinhrono Java
Script programiranje.
407
Pre nego to preemo na to, moramo znatno detaljnije razmotriti ta je asinhroni rad
i kako se on postie u JavaScriptu.
Program u delovima
Ceo svoj JS program moete napisati u jednoj .js datoteci, ali je on gotovo uvek sastavljen
od vie delova, od kojih e se samo jedan izvriti sada, dok e se preostali delovi izvriti
kasnije. Najuobiajenija jedinica za svaki deli programa jeste funkcija (function).
Problem koji veina JS programera naizgled ima jeste to to se kasnije ne dogaa ne-
posredno i odmah nakon sada. Drugim reima, poslovi koji se ne mogu zavriti sada za-
vrie se po definiciji asinhrono, pa zato nee imati blokirajue ponaanje kao to bi-
ste intuitivno oekivali ili eleli.
Razmotrite sledee:
// ajax(..) je neka funkcija iz biblioteke
var data = ajax( http://some.url.1 );
console.log( data );
// Uh! `data` najee nee sadrati Ajax rezultate
Verovatno znate da se standardni Ajax zahtevi ne izvravaju sinhrono, to znai da
funkcija ajax(..) jo nema nikakvu vrednost da vrati kako bismo je dodelili promenlji-
voj data. Kada bi funkcija ajax(..) mogla da blokira izvravanje programa dok ne stigne
odziv, onda bi se operacija dodeljivanja data = .. izvrila kako treba.
Meutim, Ajax ne radi tako. Asinhroni Ajax zahtev aljemo sada, ali emo njegove re-
zultate dobiti kasnije.
Najjednostavniji (ali svakako ne i jedini, niti obavezno najbolji!) nain da saekamo
od sada do kasnije jeste da upotrebimo funkciju, poznatu pod nazivom povratna funkci-
ja (engl. callback function):
// ajax(..) je neka funkcija iz biblioteke
ajax( http://some.url.1, function myCallbackFunction(data){
} );
Moda ste uli da je mogue slati sinhrone Ajax zahteve. Mada je to tehniki
izvodljivo, nemojte to nikad i ni u kom sluaju raditi, zato to tako blokirate ko-
risniki interfejs itaa veba (dugmad, menije, pomeranje sadraja prozora itd.)
i spreavate svaku interakciju s korisnikom. To je uasno loa ideja i trebalo bi
da je uvek izbegavate.
Pre nego to ponete da negodujete jer se ne slaete s time, rei emo da vaa elja da
izbegnete zbrku s povratnim funkcijama ne opravdava upotrebu blokirajueg, sinhro-
nog Ajaxa.
function later() {
answer = answer * 2;
console.log( Smisao ivota je:, answer );
}
function later() { .. }
Asinhronizam konzole
Ne postoji specifikacija niti skup zahteva koji bi propisivali kako treba da rade metode
console.* zato to one zvanino nisu sastavni deo JavaScripta, nego ih u JS dodaje rad-
no okruenje (videti etvrti deo ove knjige Tipovi i gramatika).
Iz tog razloga, razliiti itai veba i JS okruenja rade kako njima odgovara, to pone-
kad dovodi do zbunjujueg ponaanja.
// kasnije
console.log( a ); // ??
// jo kasnije
a.index++;
Standardno bismo oekivali da vidimo kako se stanje objekta a prikazuje onakvo ka-
kvo je bilo tano u trenutku izvravanja iskaza console.log(..), tj. da se ispie neto po-
put { index: 1 }, tako da kad se izvri sledei iskaz a.index++ on menja stanje kakvo
je bilo neposredno nakon prikazivanja stanja a.
Prethodni primer koda predstavljae objekat na vaoj konzoli najee ba onako
kako biste oekivali. Ali, moe se dogoditi da isti kd radi u situaciji gde ita veba sma-
tra da ulazno/izlazne operacije na konzoli treba da izvrava u pozadini, kada se moe do-
goditi da je u trenutku kad se objekat prikazuje na konzoli itaa veba iskaz a.index++
ve bio izvren, pa zato konzola prikazuje { index: 2 }.
Teko je tano odrediti pod kojim e uslovima U/I operacije na konzoli biti odloene,
pa ak i to da li e to biti uoljivo. Imajte samo u vidu taj mogui U/I asinhronizam u slu-
aju da pri otkrivanju greaka imate problema s objektima koji se u programu menjaju
nakon izvravanja iskaza console.log(..), ali se uprkos tome na konzoli vide neoekiva-
ne naknadne izmene.
Ako vam se dogodi takav redak sluaj, najbolje reenje je da u svom JS dibage-
ru zadate prekidne take umesto da podatke prikazujete pomou iskaza con-
sole. Drugo najbolje reenje je da napravite snimak datog objekta tako to
ga serijalizujete u promenljivu tipa string na primer, pomou metode JSON.
stringify(..).
function foo() {
a = a + 1;
}
function bar() {
a = a * 2;
}
function foo() {
a++;
b = b * a;
a = b + 3;
}
function bar() {
b--;
a = 8 + b;
b = a * 2;
}
// foo()
a++;
b = b * a;
a = b + 3;
// bar()
b--;
a = 8 + b;
b = a * 2;
a; // 11
b; // 22
Rezultat 2:
var a = 1;
var b = 2;
// bar()
b--;
a = 8 + b;
b = a * 2;
// foo()
a++;
b = b * a;
a = b + 3;
a; // 183
b; // 180
Dva mogua rezultata istog koda znae da i dalje imamo nedeterminizam! Ali to je na
nivou redosleda izvravanja funkcija (dogaaja), a ne na nivou redosleda izvravanja iskaza
programa (ili, u stvari, na nivou redosleda operacija nad izrazima) kao u sluaju niti. Dru-
gim reima, determinizam programa je bolji nego u sluaju vienitnog izvravanja.
Primenjeno na ponaanje JavaScripta, za taj nedeterminizam usled redosleda izvra-
vanja funkcija postoji uobiajen izraz stanje utrkivanja (engl. race condition) jer se funk-
cije foo() i bar() meusobno trkaju koja e se prva izvriti. Konkretno, imamo trku zato
to nema pouzdanog naina da predvidimo koju e vrednost dobiti a i b.
Istovremenost
Zamislite veb lokaciju koja prikazuje listu auriranih statusa (kao to je lista vesti na
drutvenim mreama) koja se puni dok korisnik pomera sadraj prozora. Da bi to radilo
kako treba, potrebno je da se (barem) dva zasebna procesa izvravaju istovremeno (na
primer, tokom istog vremenskog intervala, ali ne obavezno i u istom trenutku).
Re proces ovde piemo izmeu navodnika zato to to nisu pravi procesi ope-
rativnog sistema kako ih raunarska nauka definie. To su virtuelni procesi, ili
poslovi, koje ine logiki povezani sekvencijalni nizovi operacija. Re proces
koristimo umesto posao zato to ona terminoloki odgovara definiciji konce-
pata koje ovde razmatramo.
Tokom datog vremenskog intervala (nekoliko sekundi tokom kojih korisnik pomera
sadraj prozora), pokuaemo da vizuelizujemo svaki nezavisan proces kao niz doga-
aja/operacija:
Proces 1 (dogaaji onscroll):
onscroll, request 1
onscroll, request 2
onscroll, request 3
onscroll, request 4
Istovremenost|417