Eric Elliott

Follow

Jan 23, 2017 · 11 min de citit

Photo by Kabun (CC BY DD SA 2.,0)

„Master JavaScript Interviu” este o serie de mesaje menite să pregătească candidații pentru întrebări frecvente, ele sunt susceptibile de a întâlni atunci când se aplică pentru un mid de nivel superior JavaScript poziție. Acestea sunt întrebări pe care le folosesc frecvent în interviuri reale.

O promisiune este un obiect care poate produce o singură valoare un moment dat în viitor: fie un rezolvate valoare, sau un motiv pentru care nu este rezolvată (de exemplu, o eroare de rețea)., O promisiune poate fi într-una din cele 3 stări posibile: îndeplinite, respinse sau în așteptare. Promise utilizatorii pot atașa callback să se ocupe de valoarea îndeplinită sau motivul respingerii.

promisiunile sunt dornice, ceea ce înseamnă că o promisiune va începe să facă orice sarcină pe care o dați imediat ce constructorul promisiunii este invocat. Dacă aveți nevoie de leneș, consultați observabile sau sarcini.

o istorie incompletă a promisiunilor

implementări timpurii ale promisiunilor și futures (o idee similară / înrudită) au început să apară în limbi precum MultiLisp și Prolog concurente încă din anii 1980., Folosirea cuvântului „promisiune” a fost inventată de Barbara Liskov și Liuba Shrira în 1988.

prima dată când am auzit despre promisiuni în JavaScript, Node era nou și comunitatea discuta despre cel mai bun mod de a gestiona comportamentul asincron. Comunitatea a experimentat promisiuni pentru o vreme, dar în cele din urmă s-a stabilit pe eroarea standard a nodului-primele apeluri.în același timp, Dojo a adăugat promisiuni prin API-ul amânat. Creșterea interesului și a activității a dus în cele din urmă la promisiunile nou formate/o specificație concepută pentru a face diverse promisiuni mai interoperabile.,

comportamentele asincrone ale lui jQuery au fost refactorate în jurul promisiunilor. jQuery ‘ s promise support a avut asemănări remarcabile cu dojo — ul amânat și a devenit rapid cea mai frecvent utilizată implementare a promisiunii în JavaScript datorită imensei popularități a lui jQuery-pentru un timp. Cu toate acestea, nu a susținut comportamentul de înlănțuire cu două canale (îndeplinit/respins) & managementul excepțiilor pe care oamenii se bazau pentru a construi instrumente pe lângă promisiuni.,în ciuda acestor puncte slabe, Jquery a făcut oficial JavaScript promite mainstream, și mai bine stand-alone biblioteci promisiune ca Q, atunci când, și Bluebird a devenit foarte popular. jQuery implementarea incompatibilități motivat unele clarificări importante în promisiunea spec, care a fost rescris și rebranduit ca Promisiunile/O+ caietul de sarcini.,

ES6-a adus un Promite/O+ compatibil Promise global, și unele foarte importante APIs au fost construite pe partea de sus a noului standard Promit sprijin: în special WHATWG Aduce spec și Asincron Funcții standard (o etapă 3 proiectul de la momentul de acest scris).promisiunile descrise aici sunt cele care sunt compatibile cu specificațiile Promisions / A+, cu accent pe standardul ECMAScript Promise implementare.

cum funcționează promisiunile

o promisiune este un obiect care poate fi returnat sincron dintr-o funcție asincronă., O promisiune este rezolvată dacă nu este în așteptare (a fost rezolvată sau respinsă). Uneori, oamenii folosesc rezolvate și decontate să însemne același lucru: nu în așteptare.odată stabilit, o promisiune nu poate fi reinstalată. Apelarea resolve() sau reject() din nou nu va avea niciun efect. Imutabilitatea unei promisiuni stabilite este o caracteristică importantă.

promisiunile JavaScript Native nu expun stările de promisiuni. În schimb, vă așteptați să tratați promisiunea ca pe o cutie neagră., Numai funcția responsabilă pentru crearea promisiunii va avea cunoștințe despre statutul promisiunii sau acces la rezolvare sau respingere.

Aici este o funcție care returnează o promisiune care va rezolva după un anumit timp de întârziere:

așteptați — promisiunea de exemplu pe CodePen

wait(3000) apel va aștepta 3000ms (3 secunde), apoi conectați-vă 'Hello!'., Toate promisiunile compatibile cu specificațiile definesc o metodă .then() pe care o utilizați pentru a trece manipulatorii care pot lua valoarea rezolvată sau respinsă.

constructorul ES6 promise are o funcție. Această funcție are doi parametri, resolve() și reject(). În exemplul de mai sus, folosim doar resolve(), așa că am lăsat reject() din lista de parametri. Atunci noi numim setTimeout() pentru a crea întârziere, și de apel resolve() atunci când este terminat.,

puteți opțional resolve() sau reject() cu valori, care va fi trecut la funcțiile de apel invers atașat cu .then().

când am reject()cu o valoare, trec întotdeauna un obiect Error. În general, vreau două posibile stări de rezoluție: calea fericită normală sau o excepție — orice lucru care oprește calea fericită normală să se întâmple. Trecerea unui obiect Error face acest lucru explicit.,

reguli importante de promisiune

un standard pentru promisiuni a fost definit de comunitatea de specificații Promises/a+. Există multe implementări care se conformează standardului, inclusiv promisiunile JavaScript standard ECMAScript.

Promite următoarele spec trebuie să urmeze un set de reguli specifice:

  • O promisiune sau „thenable” este un obiect care furnizează un standard compatibil .then() metoda.
  • o promisiune în așteptare poate trece într-o stare îndeplinită sau respinsă.,
  • o promisiune îndeplinită sau respinsă este soluționată și nu trebuie să treacă în niciun alt stat.
  • odată ce o promisiune este stabilită, trebuie să aibă o valoare (care poate fi undefined). Această valoare nu trebuie să se schimbe.

schimbarea în acest context se referă la compararea identității (===). Un obiect poate fi folosit ca valoare îndeplinită, iar proprietățile obiectului pot suferi mutații.,

Fiecare promisiune trebuie să furnizeze un .then() metoda cu următoarea semnătură:

promise.then(
onFulfilled?: Function,
onRejected?: Function
) => Promise

.then() metoda trebuie să respecte aceste reguli:

  • Ambele onFulfilled() și onRejected() sunt opționale.
  • dacă argumentele furnizate nu sunt funcții, acestea trebuie ignorate.
  • onFulfilled() va fi apelat după ce promisiunea este îndeplinită, cu valoarea promisiunii ca prim argument.,
  • onRejected() va fi apelat după ce promisiunea este respinsă, cu motivul respingerii ca prim argument. Motivul poate fi orice valoare JavaScript validă, dar deoarece respingerile sunt în esență sinonime cu excepții, vă recomand să utilizați obiecte de eroare.
  • Nici onFulfilled() sau onRejected() poate fi numit mai mult de o dată.
  • .then() poate fi apelat de mai multe ori pe aceeași promisiune. Cu alte cuvinte, o promisiune poate fi folosit pentru a agrega callback.,
  • .then()trebuie să returneze o nouă promisiune,promise2.
  • Dacă onFulfilled() sau onRejected() întoarce o valoare x și x este o promisiune, promise2 va bloca în cu (presupun același stat și valoarea) x. În caz contrar, promise2va fi îndeplinită cu valoarea x.,
  • Dacă onFulfilled sau onRejected aruncă o excepție e, promise2 trebuie să fie respins cu e ca motiv.
  • Dacă onFulfilled nu este o funcție și promise1 este îndeplinită, promise2 trebuie să fie îndeplinite cu aceeași valoare ca promise1.,
  • Dacă onRejected nu este o funcție și promise1 este respins, promise2 trebuie să fie respins cu același motiv ca promise1.

Promise înlănțuirea

deoarece.then() returnează întotdeauna o nouă promisiune, este posibil să Lanț promisiuni cu un control precis asupra modului și în cazul în care erorile sunt tratate. Promisiuni permite să imite normale sincron cod e try/catch comportament.,ca și Codul sincron, înlănțuirea va avea ca rezultat o secvență care rulează în serie., Cu alte cuvinte, poți să faci:

fetch(url)
.then(process)
.then(save)
.catch(handleErrors)
;

Aici e un exemplu de un complex promit lanț cu mai multe respingeri:

Promit înlănțuirea comportamentul exemplu pe CodePen

Eroare de Manipulare

Rețineți că promisiunile au atât un succes și un handler de eroare, și este foarte comună pentru a vedea codul care face acest lucru:

save().then(
handleSuccess,
handleError
);

Dar ce se întâmplă dacă handleSuccess() aruncă o eroare?, Promisiunea returnată de la .then() va fi respinsă, dar nu există nimic care să surprindă respingerea — ceea ce înseamnă că o eroare în aplicația dvs. este înghițită. Hopa!din acest motiv, unii oameni consideră că codul de mai sus este un anti-model și recomandă următoarele, în schimb:

save()
.then(handleSuccess)
.catch(handleError)
;

diferența este subtilă, dar importantă. În primul exemplu, o eroare originare din save() operațiunea va fi prins, dar o eroare originare din handleSuccess() funcția va fi înghițit.,

Without .catch(), an error in the success handler is uncaught.

In the second example, .catch() will handle rejections from either save(), or handleSuccess().

With .catch(), both error sources are handled., (diagrama sursă)

desigur, save() eroare ar putea fi o rețea de eroare, întrucât handleSuccess() eroare poate fi, deoarece dezvoltatorul a uitat să se ocupe de un anumit cod de stare. Ce se întâmplă dacă doriți să le gestionați diferit? Ai putea opta pentru a le manipula atât:

save()
.then(
handleSuccess,
handleNetworkError
)
.catch(handleProgrammerError)
;

Orice ai prefera, am recomandăm să se încheie toate promit lanțuri cu un .catch(). Care este în valoare de repetarea:

am recomandăm să se încheie toate promit lanțuri cu un .catch().,

cum anulez o promisiune?

unul dintre primele lucruri pe care utilizatorii New promise le întreabă adesea este cum să anuleze o promisiune. Iată o idee: respingeți promisiunea cu” anulat ” ca motiv. Dacă aveți nevoie să o rezolvați diferit decât o eroare” normală”, faceți ramificarea în handler-ul de eroare.iată câteva greșeli comune pe care oamenii le fac atunci când își dau propria anulare a promisiunii:

Adăugare .,Anulează () la promisiunea

adăugarea .cancel() face promisiunea non-standard, dar încalcă și o altă regulă a promisiunilor: numai funcția care creează promisiunea ar trebui să poată rezolva, respinge sau anula promisiunea. Expunerea rupe acea încapsulare și încurajează oamenii să scrie cod care manipulează promisiunea în locuri care nu ar trebui să știe despre asta. Evitați spaghetele și promisiunile încălcate.unii oameni inteligenți și-au dat seama că există o modalitate de a utiliza Promise.race() ca mecanism de anulare., Problema este că controlul de anulare este preluat din funcția care creează promisiunea, care este singurul loc în care puteți desfășura activități adecvate de curățare, cum ar fi ștergerea timeout-urilor sau eliberarea memoriei prin ștergerea referințelor la date etc…

uitați să gestionați o promisiune de anulare respinsă

știați că Chrome aruncă mesaje de avertizare pe toată consola atunci când uitați să gestionați o respingere a promisiunii? Hopa!propunerea de anulare a tc39 retrasă a propus un canal de mesagerie separat pentru anulări., De asemenea, a folosit un nou concept numit token de anulare. În opinia mea, soluția ar fi considerabil umflat promisiunea spec, si singura caracteristică ar fi prevăzut că speculațiile nu sprijină în mod direct este separarea de respingeri și anulări, care, IMO, nu este necesar pentru a începe cu.

doriți să faceți comutarea în funcție de existența unei excepții sau a unei anulări? Da, absolut. Asta e treaba promisiunii? În opinia mea, nu, nu este.,

regândirea anulării promisiunii

În general, transmit toate informațiile de care are nevoie promisiunea pentru a determina modul de rezolvare / respingere / anulare la momentul creării promisiunii. În acest fel, nu este nevoie de o metodă .cancel() pe o promisiune. S-ar putea să vă întrebați cum ați putea ști dacă veți anula sau nu la momentul creării promisiunii.

” dacă nu știu încă dacă să anulez sau nu, cum voi ști ce să trec atunci când creez promisiunea?,”

dacă ar exista doar un fel de obiect care ar putea sta pentru o valoare potențială în viitor… Oh, așteptați.

valoarea pe care o transmitem pentru a reprezenta anularea sau nu ar putea fi o promisiune în sine. Iata cum ar putea arata:

Revocabile, așteptați — încercați să-l pe CodePen

Vom folosi parametrul implicit cesiunea să o spun nu pentru a anula în mod implicit. Acest lucru face ca parametrul cancel să fie convenabil opțional., Apoi am setat timeout-ul așa cum am făcut-o înainte, dar de data aceasta capturăm ID-ul timeout-ului, astfel încât să îl putem șterge mai târziu.

folosim metoda cancel.then() pentru a gestiona anularea și Curățarea resurselor. Acest lucru va rula numai în cazul în care promisiunea este anulată înainte de a avea o șansă de a rezolva. Dacă anulați prea târziu, ați ratat șansa. Trenul a părăsit stația.

notă: poate vă întrebați pentru ce este funcția noop(). Cuvântul noop înseamnă no-op, adică o funcție care nu face nimic., Fără aceasta, V8 va arunca avertismente: UnhandledPromiseRejectionWarning: Unhandled promise rejection. Este o idee bună să se ocupe întotdeauna promise respingeri, chiar dacă handler-ul este un noop().

Abstractizare Promit Anulare

Acest lucru este bine pentru un wait() cronometru, dar putem rezumat această idee mai departe pentru a îngloba tot ceea ce trebuie să vă amintiți:

  1. Respinge anula promisiunea implicit — nu vrem să anuleze sau arunca erori dacă nu anula promisiunea devine trecut în.
  2. nu uitați să efectuați curățarea atunci când respingeți pentru anulări.,
  3. amintiți-vă că onCancel curățire s-ar putea arunca o eroare, și că eroarea va avea nevoie de manipulare, de asemenea. (Rețineți că manipularea erorilor este omisă în exemplul de așteptare de mai sus — este ușor de uitat!)

să creăm un utilitar de anulare a promisiunii pe care îl puteți utiliza pentru a încheia orice promisiune., De exemplu, să se ocupe de cererile de rețea, etc… semnătura va arata astfel:

speculation(fn: SpecFunction, shouldCancel: Promise) => Promise

SpecFunction este la fel ca funcția pe care o va trece în Promise constructor, cu o singură excepție — este nevoie de un onCancel() handler:

SpecFunction(resolve: Function, reject: Function, onCancel: Function) => Void

Rețineți că acest exemplu este doar o ilustrare să-ți faci o idee de cum functioneaza. Există și alte cazuri de margine pe care trebuie să le luați în considerare., De exemplu, în această versiune, handleCancel va fi apelat dacă anulați promisiunea după ce este deja rezolvată.

am implementat o versiune de producție menținută a acestui lucru cu cazuri de margine acoperite ca biblioteca open source, speculații.

să folosim abstractizarea îmbunătățită a bibliotecii pentru a rescrie utilitarul wait() care poate fi anulat înainte., Instalați mai întâi speculații:

npm install --save speculation

Acum puteți importa și de a folosi:

Acest lucru simplifică lucrurile un pic, pentru că nu trebuie să vă faceți griji despre noop(), prinderea erori în onCancel(), funcția sau alte cazuri de margine. Aceste detalii au fost abstracte departe de speculation(). Verificați – l și nu ezitați să-l utilizați în proiecte reale.,

servicii suplimentare Nativ JS Promit

nativ Promise obiect are unele chestii in plus ai putea fi interesat în:

  • Promise.reject() returnează un respins promisiunea.
  • Promise.resolve() returnează o promisiune rezolvată.
  • Promise.race() nevoie de o matrice (sau orice iterable) și returnează o promisiune care rezolvă cu valoarea primului rezolvate promisiunea în iterable, sau respinge cu motivul de prima promisiune pe care o respinge.,
  • Promise.all() nevoie de o matrice (sau orice iterable) și returnează o promisiune care rezolvă atunci când toate promisiunile în iterable argument trebuie rezolvate, sau respinge cu motivul de prima trecut promit că respinge.

Concluzie

Promisiuni au devenit o parte integrantă a mai multor expresii în JavaScript, inclusiv WHATWG Aduce standard folosit pentru cele mai moderne cereri ajax, și Asincron Funcții standard folosit pentru a face codul asincron uite sincron.,

funcțiile asincrone sunt etapa 3 la momentul acestei scrieri, dar prezic că vor deveni în curând o soluție foarte populară, foarte frecvent utilizată pentru programarea asincronă în JavaScript — ceea ce înseamnă că învățarea aprecierii promisiunilor va fi și mai importantă pentru dezvoltatorii JavaScript în viitorul apropiat.

de exemplu, dacă utilizați Redux, vă sugerez să consultați redux-saga: o bibliotecă utilizată pentru a gestiona efectele secundare în Redux, care depinde de funcțiile asincrone din întreaga documentație.,sper că chiar și utilizatorii cu experiență promit să înțeleagă mai bine ce promisiuni sunt și cum funcționează și cum să le folosească mai bine după ce au citit acest lucru.

explorați seria

  • ce este un Closure?
  • care este diferența dintre moștenirea clasei și cea prototipică?
  • ce este o funcție pură?
  • ce este compoziția funcției?
  • ce este programarea funcțională?
  • ce este o promisiune?
  • Soft Skills

Lasă un răspuns

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *