Programiranje

Asinhroni JavaScript: razloženi povratni klici in obljube

Ukvarjanje z asinhrono kodo, kar pomeni, da se koda ne izvede takoj, kot so spletne zahteve ali časovniki, je lahko težavno. JavaScript nam ponuja dva načina, kako rešiti asinhrono vedenje: povratne klice in obljube.

Povratni klici so bili edini izvorno podprt način za obravnavo async kode do leta 2016, ko je Obljubi predmet je bil uveden v jezik. Vendar so razvijalci JavaScript podobne funkcije izvajali že leta, preden so na sceno prišle obljube. Oglejmo si nekaj razlik med povratnimi klici in obljubami in si oglejmo, kako se spopadamo z usklajevanjem več obljub.

Asinhrone funkcije, ki uporabljajo povratne klice, vzamejo funkcijo kot parameter, ki bo poklican, ko bo delo končano. Če ste uporabili kaj takega setTimeout v brskalniku ste uporabili povratne klice.

// Povratni klic lahko določite ločeno ...

naj myCallback = () => {

console.log ('Poklican!');

};

setTimeout (myCallback, 3000);

//… vendar je pogosto tudi, da so povratni klici definirani v vrstici

setTimeout (() => {

console.log ('Poklican!');

}, 3000);

Običajno ga funkcija, ki sprejme povratni klic, vzame kot zadnji argument. To ni zgoraj, zato se pretvarjajmo, da se imenuje nova funkcija počakaj to je prav tako setTimeout vendar prva dva argumenta vzame v nasprotnem vrstnem redu:

// Našo novo funkcijo bi uporabili tako:

waitCallback (3000, () => {

console.log ('Poklican!');

});

Vgnezdeni povratni klici in piramida pogube

Povratni klici se dobro obnesejo pri obdelavi asinhrone kode, vendar postanejo zapleteni, ko začnete usklajevati več asinhronih funkcij. Če smo na primer želeli počakati dve sekundi in nekaj zabeležiti, nato počakati tri sekunde in zabeležiti nekaj drugega, nato počakati štiri sekunde in zabeležiti nekaj drugega, se naša sintaksa globoko ugnezdi.

// Našo novo funkcijo bi uporabili tako:

waitCallback (2000, () => {

console.log ('Prvi povratni klic!');

waitCallback (3000, () => {

console.log ('Drugi povratni klic!');

waitCallback (4000, () => {

console.log ('Tretji povratni klic!');

    });

  });

});

To se morda zdi nepomemben primer (in tudi je), vendar ni nič nenavadnega, če pošljete več spletnih zahtev zapored na podlagi rezultatov vrnitve prejšnje zahteve. Če vaša knjižnica AJAX uporablja povratne klice, se bo prikazala zgornja struktura. V primerih, ki so globlje ugnezdeni, boste videli tisto, kar imenujemo piramida pogube, ki je svoje ime dobila po obliki piramide, narejeni v razmaknjenem presledku na začetku vrstic.

Kot lahko vidite, naša koda postane strukturno pokvarjena in težje berljiva pri obravnavi asinhronih funkcij, ki se morajo izvajati zaporedno. Ampak postane še bolj zapleteno. Predstavljajte si, če bi radi sprožili tri ali štiri spletne zahteve in izvedli neko nalogo šele potem, ko se vse vrnejo. Svetujem vam, da poskusite to storiti, če še niste naleteli na izziv.

Lažja asinhronizacija z obljubami

Promises zagotavljajo prožnejši API za obravnavo asinhronih nalog. Zahteva, da je funkcija napisana tako, da vrne a Obljubi objekt, ki ima nekaj standardnih funkcij za obdelavo nadaljnjega vedenja in usklajevanje več obljub. Če je naša waitCallback funkcija je bila Obljubina podlagi bi potreboval le en argument, kar je milisekunde čakanja. Vsaka nadaljnja funkcionalnost bi bila priklenjen od obljube. Naš prvi primer bi bil videti takole:

naj myHandler = () => {

console.log (‘Poklican!’);

};

waitPromise (3000) .tem (myHandler);

V zgornjem primeru waitPromise (3000) vrne a Obljubi objekt, ki ima nekaj metod, ki jih lahko uporabimo, kot je potem. Če bi hoteli izvajati več asinhronih funkcij eno za drugo, bi se lahko z obljubami izognili piramidi pogube. Ta koda, napisana v podporo naši novi obljubi, bi izgledala takole:

// Ne glede na to, koliko zaporednih asinhronih nalog imamo, nikoli ne naredimo piramide.

waitPromise (2000)

.tem (() => {

console.log ('Prvi povratni klic!');

vrnitev waitPromise (3000);

  })

.tem (() => {

console.log ('Drugi povratni klic!');

vrnitev waitPromise (4000);

  })

.tem (() => {

console.log ('Drugi povratni klic!');

vrnitev waitPromise (4000);

  });

Še bolje, če bi morali usklajevati asinhrone naloge, ki podpirajo obljube, bi lahko uporabili vse, ki je statična metoda na Obljubi predmet, ki sprejme več obljub in jih združi v eno. To bi izgledalo takole:

Promise.all ([

waitPromise (2000),

waitPromise (3000),

počakajPromise (4000)

]). then (() => console.log ('Vse je narejeno!'));

Prihodnji teden bomo podrobneje raziskovali, kako obljube delujejo in kako jih idiomatsko uporabiti. Če se šele učite JavaScript ali vas zanima preverjanje znanja, poskusite waitCallback ali poskusite doseči ekvivalent Promise.all z povratnimi klici.

Kot vedno se obrnite na mene na Twitterju s kakršnimi koli komentarji ali vprašanji.