Eric Elliott

Seuraa

Jan 23, 2017 · 11 min lue

Kuva Kabun (CC BY NC SA 2.,0)

”Hallita JavaScript Haastattelu” on useita virkoja, joiden tarkoituksena on valmistella ehdokkaita yleisiä kysymyksiä, ne ovat todennäköisesti kohtaavat hakiessaan mid senior-tason JavaScript-asentoon. Näitä kysymyksiä käytän usein oikeissa haastatteluissa.

lupaus on esine, joka voi tuottaa yhden arvon joskus tulevaisuudessa: joko ratkaistu arvo, tai syystä, että se ei ole ratkaistu (esim., a network error occurred)., Lupaus voi olla jossakin 3 mahdollisesta valtiosta: täyttynyt, hylätty tai vireillä. Lupauksen käyttäjät voivat liittää takaisinkutsuja käsitelläkseen täyttyneen arvon tai hylkäämisen syyn.

lupaukset ovat innokkaita, eli lupaus alkaa tehdä mitä tahansa tehtävää, kun lupauksen rakentajaan vedotaan. Jos tarvitset laiska, tutustu observables tai tehtäviä.

Epätäydellinen Historia Lupaa

Varhainen toteutuksia lupauksia ja futuurit (samanlainen / liittyvä ajatus) alkoi ilmestyä vuonna kieliä, kuten MultiLisp ja Samanaikainen Prolog jo 1980-luvulla., Sana ”lupaus” keksi Barbara Liskov ja Liuba Shrira vuonna 1988.

ensimmäistä kertaa kuulin lupauksista Javascriptissä, Node oli upouusi ja yhteisö keskusteli parhaasta tavasta käsitellä asynkronista käyttäytymistä. Yhteisön kokeillut lupaa jonkin aikaa, mutta lopulta ratkaistaan Solmu-standardi virhe-ensimmäinen kutsuja.

samoihin aikoihin Dojo lisäsi lupauksia laskennallisen API: n kautta. Kasvava kiinnostus ja toiminta johtivat lopulta siihen, että vastaperustetut lupaukset/eritelmä, jonka tarkoituksena on tehdä erilaisista lupauksista yhteentoimivampia.,

jQueryn async-käyttäytymismallit pantiin uusiksi lupausten ympärille. jQuery on lupaus tuki oli merkittävä yhtäläisyyksiä Dojo on Laskennallinen, ja se tuli nopeasti yleisimmin käytetty lupauksen täytäntöönpano JavaScript, koska jQuery on valtavan suosion — aikaa. Kuitenkin, se ei tue kahden kanavan (täytetty/hylätty) ketjutus käyttäytyminen & poikkeus management, että ihmiset luottivat rakentaa työkaluja päälle lupauksia.,

noista heikkouksista huolimatta jQuery teki JavaScript-lupauksista virallisesti valtavirtaa, ja paremmin stand-alone promise-kirjastot kuten Q, When, ja Bluebird tuli hyvin suosituksi. jQuery täytäntöönpanoa yhteensopimattomuudet motivoitunut joitakin tärkeitä selvennyksiä lupaus spec, joka oli kirjoitettu uudelleen ja rebranded kuin Lupaukset/A+ erittely.,

ES6 toi Lupauksia/A+ – yhteensopiva Promise maailmanlaajuinen, ja joitakin erittäin tärkeitä APIs oli rakennettu päälle uusi standardi Lupaa tukea: erityisesti WHATWG Noutaa spec ja Async Toiminnot-standardin mukaisesti (vaihe 3 luonnos tuolloin tätä kirjoitettaessa).

lupaa kuvata tässä ovat ne, jotka ovat yhteensopivia Lupaa/A+ erittely, jossa keskitytään ECMAScript standardi Promise toteutus.

Miten Lupaukset Toimi

lupaus on esine, joka voidaan palauttaa synkronisesti alkaen asynkroninen toiminta., Se tulee olemaan yksi 3 mahdollista tilaa:

lupaus on ratkaistu, jos se ei ole vireillä (se on ratkaistu tai hylätty). Joskus ihmiset käyttävät ratkaistua ja vakiintunutta tarkoittamaan samaa asiaa:ei vireillä.

kun asia on ratkaistu, lupausta ei voi uudelleensijoittaa. Soittamalla resolve() tai reject() taas ei ole vaikutusta. Vakiintuneen lupauksen muuttumattomuus on tärkeä piirre.

natiivi JavaScript promises don ’ t expose promise states. Sen sijaan lupausta odotetaan pidettävän mustana laatikkona., Ainoa toiminto, vastuussa luoda lupaus on tietoa lupaus tilan tai pääsy ratkaista tai hylätä.

Tässä on funktio, joka palauttaa lupaus, joka ratkaisee tietyn aikaviiveen:

odota — lupaus esimerkki siitä, CodePen

Meidän wait(3000) puhelu odottaa 3000ms (3 sekuntia), ja sitten kirjaudu 'Hello!'., Kaikki spec-yhteensopiva lupaa määritellä .then() menetelmä, jolla voit siirtää käsittelijät, jotka voivat ottaa ratkaistu tai hylätään arvo.

ES6 promise constructor ottaa funktion. Toiminto vaatii kaksi parametrit, resolve() ja reject(). Yllä olevassa esimerkissä käytetään vain resolve(), joten lähdin reject() pois parametrilistalta. Sitten me kutsumme setTimeout() luoda viive, ja soittaa resolve() kun se on valmis.,

vaihtoehtoisesti resolve() tai reject() arvot, jotka välitetään soittopyyntö toiminnot kiinnitetty .then().

Kun I reject() arvo, olen aina siirtää Error objekti. Yleensä haluan kaksi mahdollista päätöslauselmaa: normaalin onnellisen tien tai poikkeuksen-kaiken, mikä estää normaalin onnellisen polun tapahtumasta. Error – objektin ohittaminen tekee tästä yksiselitteisen.,

tärkeät Lupaussäännöt

lupausten standardin määritteli Promises / a+ specification community. On olemassa monia toteutuksia, jotka ovat standardin mukaisia, mukaan lukien JavaScript-standardi ECMAScript lupaa.

Lupaa seuraavat spec täytyy noudattaa tiettyjä sääntöjä:

  • lupaus tai ”thenable” on esine, joka toimittaa standardin mukainen .then() menetelmä.
  • vireillä oleva lupaus voi siirtyä täyttyneeseen tai hylättyyn tilaan.,
  • täyttynyt tai hylätty lupaus ratkaistaan, eikä se saa siirtyä mihinkään muuhun valtioon.
  • Kun lupaus on ratkaistu, se on oltava arvo (joka voi olla undefined). Tämä arvo ei saa muuttua.

muutos tässä yhteydessä viittaa identiteettiin (===) vertailuun. Objektia voidaan käyttää täytettynä arvona, ja objektin ominaisuudet voivat muuntua.,

Jokainen lupaus on toimitettava .then() menetelmä seuraavat allekirjoitus:

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

.then() menetelmä on noudatettava näitä sääntöjä:

  • Sekä onFulfilled() ja onRejected() ovat valinnaisia.
  • Jos esitetyt argumentit eivät ole funktioita, ne on jätettävä huomiotta.
  • onFulfilled() kutsutaan lupauksen täyttymisen jälkeen lupauksen arvo ensimmäisenä argumenttina.,
  • onRejected() kutsutaan sen jälkeen, kun lupaus on hylätty, syy hylkäämiseen ensimmäisenä argumenttina. Syy voi olla mikä tahansa kelvollinen JavaScript-arvo, mutta koska hylkäämiset ovat lähinnä synonyymi poikkeuksia, en suosittele Virhe esineitä.
  • Ei onFulfilled() eikä onRejected() voidaan kutsua useammin kuin kerran.
  • .then() voidaan kutsua monta kertaa saman lupauksen. Toisin sanoen lupauksella voidaan koota yhteen takaisinkutsuja.,
  • .then() täytyy palauttaa uuden lupauksen, promise2.
  • Jos onFulfilled() tai onRejected() paluu arvo x ja x on lupaus, promise2 lukita kanssa (oletetaan, että saman valtion ja arvo) x. Muussa tapauksessa promise2 täytetään arvo x.,
  • Jos joko onFulfilled tai onRejected heittää poikkeus e, promise2 on hylättävä e syyksi.
  • Jos onFulfilled ei ole funktio ja promise1 täyttyy, promise2 tulee täyttää sama arvo kuin promise1.,
  • Jos onRejected ei ole funktio ja promise1 hylätään, promise2 on hylättävä samasta syystä, kuin promise1.

Lupaus Ketjutus

Koska .then() aina palauttaa uuden lupauksen, se on mahdollista ketju lupaa tarkat valvoa, miten ja missä virheitä käsitellään. Lupauksia avulla voit jäljitellä normaalia synkroninen koodi try/catch käyttäytyminen.,

Kuten synkroninen koodi, ketjutus johtaa sekvenssi, joka toimii serial., Toisin sanoen, voit tehdä:

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

Tässä on esimerkki monimutkaisesta lupaus ketju, jossa on useita hylkäämisestä:

Lupaus käyttäytyminen ketjutus esimerkiksi CodePen

Virheiden Käsittely

Huomaa, että lupaukset ovat molemmat menestys ja virheen käsittelytoiminnon, ja se on hyvin yleistä nähdä koodi, joka tekee tämän:

save().then(
handleSuccess,
handleError
);

Mutta mitä tapahtuu, jos handleSuccess() heittää virheen?, Lupaus palannut .then() hylätään, mutta siellä ei ole mitään kiinni hylkääminen — mikä tarkoittaa, että virhe-sovellus saa niellä. Hupsista!

tästä syystä, jotkut ihmiset pitävät yllä oleva koodi on anti-mallia, ja suosittelemme seuraavia, sen sijaan:

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

ero on hiuksenhieno, mutta tärkeä. Ensimmäisessä esimerkissä virhe peräisin save() toiminta on kiinni, mutta virhe on peräisin handleSuccess() – toiminto ei saa niellä.,

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., (kaavio lähde)

tietenkin save() virhe saattaa olla verkostoitumisen virhe, kun handleSuccess() virhe voi olla, koska kehittäjä unohti käsitellä tietyn tilan koodi. Entä jos haluat käsitellä niitä eri tavalla? Voisit halutessaan käsitellä niitä sekä:

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

Mitä ikinä haluat, suosittelen päättyy kaikki lupaavat ketjut .catch(). Se on syytä toistaa:

suosittelen päättyy kaikki lupaavat ketjut .catch().,

miten Perun lupauksen?

ensimmäisiä asioita, joita new promise-käyttäjät usein ihmettelevät, on se, miten lupaus perutaan. Tässä on idea: hylkää lupaus, jonka syy on ”peruttu”. Jos sinun täytyy käsitellä sitä eri tavalla kuin ”normaali” virhe, tee aluevaltaus virhe handler.

Tässä muutamia yleisiä virheitä, joita ihmiset tekevät rullatessaan omaa lupaustaan peruutus:

lisäten .,cancel() lupaus

Lisäämällä .cancel() tekee lupauksen, ei-standardi, mutta se myös rikkoo toinen sääntö lupaa: Vain toiminto, joka luo lupaus olisi voitava ratkaista, hylätä tai peruuttaa lupaa. Sen paljastaminen rikkoo kapselointia ja kannustaa ihmisiä kirjoittamaan koodia, joka manipuloi lupausta paikoissa, joiden ei pitäisi tietää siitä. Vältä spagettia ja rikottuja lupauksia.

Unohtamatta siivota

Jotkut viisaat ihmiset ovat saaneet selville, että on olemassa tapa käyttää Promise.race() peruutus mekanismi., Ongelmana on, että peruuttamisen ohjaus on otettu toiminto, joka luo lupaus, joka on ainoa paikka, että voit tehdä kunnon siivous toimintaa, kuten clearing aikakatkaisut tai vapauttaa muistia poistamalla viittaukset tiedot, jne…

Unohtamatta käsitellä hylkäsi peruuttaa lupaa

tiesitkö, että Chrome heittää varoitus viestejä ympäri konsoli, kun et unohda käsitellä lupaus hylkääminen? Hupsista!

Liian monimutkaisia

peruuttanut TC39 ehdotus peruutus ehdotti erillistä viestintäkanavaa peruutuksista., Se käytti myös uutta konseptia nimeltä peruutusmerkki. Mielestäni ratkaisu olisi huomattavasti paisunut lupaus spec, ja ainoa ominaisuus se on, edellyttäen, että spekulaatiot eivät ole suoraan tuki on erottaminen hylkäämisestä ja peruutuksia, jotka IMO, ei ole tarpeen aloittaa.

haluatko tehdä vaihtamisen riippuen siitä, onko kyseessä poikkeus vai peruutus? Ehdottomasti. Onko se lupauksen tehtävä? Minun mielestäni ei ole.,

Uudelleenarviointia Lupaus Peruutus

Yleensä, minä siirtää kaikki tiedot, lupaus on selvittää, miten ratkaista / hylkää / peruuta milloin lupauksen luomisen aika. Näin ei tarvita .cancel() – menetelmää lupauksesta. Saatat ihmetellä, miten voit mahdollisesti tietää, aiotko peruuttaa lupauksen luomisen aikaan.

”Jos en vielä tiedä, onko tai ei peruuta, miten voin tietää, mitä tapahtuu, kun luon lupaus?,”

Jos vain olisi jokin esine, joka voisi olla potentiaalinen arvo tulevaisuudessa… hetkinen.

arvo, jonka siirrämme edustamaan sitä, voisiko peruuttaminen olla lupaus itsessään. Tässä on, miten se voisi näyttää:

Peruutettavissa odottaa kokeilla sitä CodePen

käytämme oletuksena parametri tehtävän kertoa se ei peruuttaa oletuksena. Siksi cancel parametri on sopivasti valinnainen., Sitten sovimme aikalisän kuten ennenkin, mutta tällä kertaa nappaamme aikalisän tunnuksen, jotta voimme selvittää sen myöhemmin.

käytämme cancel.then() tapa käsitellä peruutus ja resurssien uudelleenjärjestäminen. Tämä onnistuu vain, jos lupaus peruuntuu ennen kuin sillä on mahdollisuus ratkaista asia. Jos peruutat liian myöhään, menetit tilaisuutesi. Juna lähti asemalta.

Huomautus: Sinulla voi olla miettimättä, mitä noop() funktio on. Sana noop tarkoittaa ei-op, mikä tarkoittaa funktiota, joka ei tee mitään., Ilman sitä, V8 heittää varoitukset: UnhandledPromiseRejectionWarning: Unhandled promise rejection. Se on hyvä idea aina käsitellä lupaus hylkäämisestä, vaikka handler on noop().

Hahmotuskykyyn Lupaus Peruutus

– Tämä on hieno wait() ajastin, mutta voimme abstrakti tätä ajatusta edelleen kiteyttää kaiken, sinun täytyy muistaa:

  1. Hylkää peruuta-lupaus oletuksena — emme halua peruuttaa tai heittää virheitä, jos ei peruuttaa lupaa saa hyväksyttiin.
  2. Muista suorittaa siivous, kun hylkäät peruutuksista.,
  3. muista, että onCancel siivous saattaa itsessään heittää virheen, ja sekin virhe tarvitsee käsittelyä. (Huomaa, että virheenkäsittely on jätetty pois yllä olevasta odotusesimerkistä-se on helppo unohtaa!)

Let ’ s luoda peruutettavissa lupaus apuohjelma, jonka voit käyttää, kääri mitään luvata., Esimerkiksi, käsitellä verkon pyyntöjä, jne… allekirjoitus näyttää tältä:

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

SpecFunction on aivan kuin toiminta olisi kulkeutua Promise konstruktori, jolla on yksi poikkeus — se vie onCancel() handler:

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

Huomaa, että tämä esimerkki on vain esimerkki antaa sinulle ydin, miten se toimii. On joitakin muita reuna tapauksissa sinun täytyy ottaa huomioon., Esimerkiksi tässä versiossa, handleCancel kutsutaan jos peruutat lupaus, kun se on jo ratkaistu.

olen pannut ylläpitää tuotanto-versio, jossa reuna tapauksissa kattaa sekä avoimen lähdekoodin kirjasto, Spekulointia.

katsotaanpa käyttää parannettu kirjasto abstraktio kirjoittaa peruutettavissa wait() apuohjelman ennen., Asenna ensin spekulointia:

npm install --save speculation

Nyt voit tuoda ja käyttää sitä:

Tämä yksinkertaistaa asioita hieman, koska sinun ei tarvitse murehtia noop() kiinni virheitä onCancel(), toiminto tai muita reuna tapauksissa. Nämä yksityiskohdat on abstrahoitu pois speculation(). Tutustu ja vapaasti käyttää sitä todellisissa projekteissa.,

Ekstrat Native JS Lupaus

kotoisin Promise objekti on ylimääräistä tavaraa, saatat olla kiinnostunut:

  • Promise.reject() palauttaa hylätty lupaus.
  • Promise.resolve() palauttaa ratkaistu lupaus.
  • Promise.race() vie array (tai iterable) ja palaa lupauksen, joka ratkaisee arvo ensimmäinen ratkaistu lupaus iterable, tai hylkää, joiden vuoksi lupaa, ettei hylkää.,
  • Promise.all() vie array (tai iterable) ja palaa lupauksen, joka ratkaisee, kun kaikki lupaukset iterable väite on ratkaistu, tai hylkää syy ensimmäisen kulunut lupaa, ettei hylkää.

Johtopäätös

Lupauksia on tullut olennainen osa useita sanontojen JavaScript, mukaan lukien WHATWG Noutaa käytetty standardi moderni ajax pyyntöjä, ja Async Toiminnot standardi, jota käytetään tehdä asynkroninen koodi näyttää synkroninen.,

Ajastetut toiminnot ovat vaiheessa 3 tuolloin tätä kirjoitettaessa, mutta en ennustavat, että ne pian tullut erittäin suosittu, hyvin yleisesti käytetty ratkaisu asynkroninen ohjelmointi JavaScript — mikä tarkoittaa, että opettelen arvostamaan lupaa on jopa tärkeämpää JavaScript kehittäjät lähitulevaisuudessa.

esimerkiksi, jos käytät Redux, ehdotan, että voit tarkistaa redux-saaga: kirjaston avulla voidaan hallita sivuvaikutuksia Redux joka riippuu async toimintoja koko dokumentointi.,

toivon kokeneidenkin lupausten käyttäjien ymmärtävän paremmin, mitä lupaukset ovat ja miten ne toimivat, ja miten niitä käytetään paremmin tämän lukemisen jälkeen.

tutki sarjaa

  • mikä on sulkeminen?
  • mikä on luokan ja Prototyyppiperinnön ero?
  • mikä on puhdas funktio?
  • mikä on funktion koostumus?
  • mikä on funktionaalista ohjelmointia?
  • mikä on lupaus?
  • Soft Skills

Vastaa

Sähköpostiosoitettasi ei julkaista. Pakolliset kentät on merkitty *