În prima parte a acestui tutorial, am învățat principiile din spatele programării asincrone și folosind callback-urile. Pentru a examina, programarea asincronă ne permite să scriem cod care nu este blocat executând mai târziu sarcini de blocare. Funcția de returnare a apelurilor oferă o modalitate de a sincroniza execuția codului nostru.
Cu toate acestea, inversarea apelurilor în mod repetat nu este un model bun de urmat. Aici vin promisiuni de salvare. Promisiunile au fost folosite pentru o perioadă în bibliotecile JavaScript, dar acum le puteți folosi în mod natural în codul dvs. Funcțiile Async se îmbunătățesc pe baza promisiunilor, permițându-ne să ne scriem sarcinile una după alta, fără să ne mai facem griji cu privire la calendarul execuției lor.
Să aruncăm o privire la ceea ce promisiunea este conceptuală. Imaginați-vă scenariul în care faceți cumpărături online și achiziționați o pereche de pantofi. Când ieșiți, primiți un rezumat al achiziției.
Această confirmare a comenzii este ca o promisiune. Promisiunea este garanția că veți primi ceva mai târziu de la companie. În timp ce comanda dvs. este în așteptare, viața dvs. nu se oprește, bineînțeles. Continuați să faceți alte sarcini, cum ar fi navigarea pe internet. În cazul în care comanda dvs. este îndeplinită, veți primi un e-mail cu informațiile de expediere. Este posibil ca comanda dvs. să fie respinsă. Produsul pe care l-ați comandat poate fi în afara stocului sau ar putea apărea o problemă cu metoda dvs. de plată. În acest caz, veți primi un e-mail care vă va spune despre eroare.
În codul de vorbire, o promisiune este un obiect care asigură că vom obține o valoare viitoare pentru cererea noastră dacă reușește sau nu. Aceasta este forma generală pentru crearea și folosirea unei promisiuni:
funcția task1 () returnați noua promisiune (funcția (rezolvare, respingere) rezolva (date); respinge (eroare);); task1 () .then (functie (rezultat) console.log (rezultat);) .catch (functie (eroare) console.log (eroare););
Pentru a crea o promisiune, instanțiați un obiect promis și scrieți codul asincron în cadrul funcției de apel invers a promisiunii. Datele pe care doriți să le returnați din promisiune sunt transmise ca un argument către rezolva
Funcția dvs. și mesajul de eroare este trecut în respinge
funcţie. Noi lanțem împreună promisiunile folosind atunci
metodă. Aceasta ne permite să executăm secvențial sarcinile.
Dacă trebuie să transmitem rezultatele unei sarcini la următoarea sarcină, o vom returna în atunci
metodă. Poate că ne dorim să promovam împreună promisiunile atunci când suntem interesați să transformăm valorile sau trebuie să executăm codul nostru într-o anumită ordine. La sfârșitul lanțului, ne prind erorile. Dacă apare o eroare în oricare dintre sarcinile noastre, sarcinile rămase sunt sărite și eroarea este trimisă blocului nostru de captură.
În prima parte a acestui tutorial, am folosit callbacks pentru a deschide un fișier și a prelua o postare și comentariile sale. Acesta este cel care arată codul complet folosind promisiunile:
const fs = necesită ("fs"); const path = necesită ('path'); const posturiUrl = path.join (__ dirname, 'db / posts.json'); const constUrl = path.join (__ dirname, 'db / comments.json'); // returnați datele din funcția noastră de fișier loadCollection (url) return new Promise (funcție (rezolvare, respingere) fs.readFile (url, 'utf8', funcție (eroare, date) if (error) eroare '); altceva resolve (JSON.parse (data)););); // returneaza un obiect prin functia id getRecord (colectie, id) returneaza noua Promise (functie (rezolva, respinge) const data = collection.find (function (element) return element.id == id; rezolva (date);); // returnează o serie de comentarii pentru o funcție post getCommentsByPost (comments, postId) returnează comments.filter (funcția (comment) return comment.postId == postId;); // codul de initializare loadCollection (postsUrl) .then (functie (posturi) return getRecord (posturi, "001");) .then (function (post) console.log (post) return loadCollection (commentsUrl); ) .then (funcția (comentarii) const postComments = getCommentsByPost (comentarii, "001"); console.log (postComments);)) .catch (funcția (eroare) console.log (error);
Diferența este că metoda noastră de a deschide fișierul este acum înfășurată într-un obiect promis. Și în loc de a ne încadra sarcinile cu apeluri, acestea sunt înlănțuite împreună cu atunci
.
După cum puteți vedea, nu am eliminat nevoia de apelări. Noi le folosim doar în mod diferit. Înainte, ne-am imbricat callback-urile, astfel încât să putem continua execuția codului nostru în următoarea sarcină.
Acest lucru îmi amintește de când sunam la serviciul clienți despre o problemă și în loc de agentul care rezolvă problema mea, mă transfer la altcineva. Că altcineva poate sau nu poate rezolva apelul, dar în ceea ce privește primul agent este responsabilitatea altcuiva.
Cu promisiuni, vom obține ceva înapoi înainte de a merge la următoarea sarcină. Dacă avem nevoie să purtăm acel ceva la următoarea continuare a codului nostru, putem folosi a atunci
afirmație.
Folosind promisiunile, scrieți un program care va deschide un fișier de utilizatori, obține informații despre utilizator, apoi deschideți un fișier de postări și tipăriți toate postările utilizatorului.
Promisiunile reprezintă o îmbunătățire a designului programului nostru, dar putem face mai bine. Ar fi foarte convenabil dacă ne-am putea executa sarcinile în mod sincron ca acesta:
sarcina 1(); task2 (); task3 ();
Ei bine, putem cu asincia / asteptarea modelului. Pentru a face acest lucru, începem prin împachetarea sarcinilor noastre într-o funcție async. Această funcție returnează o promisiune. Apoi implementăm gestionarea erorilor prin împachetarea sarcinilor noastre în interiorul unui încearcă să prinzi
afirmație.
Dacă promisiunea este îndeplinită, ea va îndeplini toate sarcinile care au fost în interiorul nostru încerca
bloc. Dacă este respinsă, captură
bloc va fi executat. Adăugarea aștepta
cuvântul cheie înainte de orice sarcină întrerupe programul nostru până la finalizarea sarcinii.
Aceasta este forma generală pentru utilizarea funcțiilor de asincronizare:
funcția async initTasks () try const a = await task1 (); const b = așteaptă task2 (); const c = așteaptă task3 (); // face ceva cu a, b, și c captură (eroare) // face ceva cu obiectul de eroare initTasks ();
Folosind acest model, putem rescrie modul în care executăm codul nostru în exemplul nostru de fișiere.
funcția async getPost () încercați const posts = await loadCollection (postsUrl); const post = aștepta getRecord (posturi, "001"); const comments = așteaptă loadCollection (commentsUrl); const postComments = asteapta getCommentsByPost (comentarii, post.id); console.log (post); console.log (postComments); captură (eroare) console.log (eroare); getPost ();
Îmi place structurarea codului asincron cu a încearcă să prinzi
deoarece separă în mod clar codul de manipulare a erorilor de codul obișnuit. Dacă vreunul din codul nostru încerca
bloc cauzează o eroare, va fi tratată de către captură
bloc. În plus, putem adăuga a in cele din urma
bloc care va executa cod, indiferent dacă sarcinile noastre reușesc sau nu.
Un exemplu de utilizare a acestui model este când avem codul de curățare pe care trebuie să-l executăm. Acest cod nu trebuie neapărat să fie inclus în a in cele din urma
bloc. Poate fi scris după captură
declarație, și va executa. Promisiunile nu au construit această sintaxă atunci
declarație după noi captură
pentru a obține același efect.
Folosind async / await, scrieți un program care va deschide un fișier de utilizatori, obține informații despre utilizator, apoi deschideți un fișier de postări și tipăriți informațiile utilizatorului și toate postările lor.
Revocările nu sunt în mod inerent răul. Transmiterea funcțiilor în alte funcții este un model util în JavaScript. Comenzile de returnare devin o problemă atunci când le folosim pentru a controla fluxul logicii aplicației noastre. Deoarece JavaScript este asincron, trebuie să avem grijă cum scriem codul nostru, deoarece sarcinile nu vor termina neapărat în ordinea în care au fost scrise. Nu este un lucru rău pentru că nu vrem să blocăm continuarea programului.
Promisiunile sunt un model mai bun pentru scrierea codului asincron. Ele nu rezolvă doar aglomerația inversărilor inversate, dar ele păstrează și controlul rezultatului unei sarcini în cadrul acestei sarcini. Trecerea controlului la o altă sarcină, indiferent dacă acea sarcină este codul propriu sau un API terț, face ca codul nostru să fie mai puțin fiabil. În cele din urmă, funcțiile de asincracție ne permit să scriem codul nostru în mod sincron, ceea ce este mult mai intuitiv și mai ușor de înțeles.