Eric Elliott

Kövesse

Jan 23, 2017 · 11 perc olvassa el a

Fotó: Kabun (CC BY NC-SA 2.,0)

” Master the JavaScript Interview ” egy sor hozzászólás célja, hogy felkészítse a jelölteket a gyakori kérdésekre, amelyekkel valószínűleg találkoznak, amikor középszintű JavaScript pozícióra jelentkeznek. Ezek olyan kérdések, amelyeket gyakran használok valódi interjúkban.

Az ígéret olyan objektum, amely a jövőben valamikor egyetlen értéket hozhat létre: vagy megoldott értéket, vagy annak okát, hogy nem oldódott meg (például hálózati hiba történt)., Az ígéret lehet az egyik 3 lehetséges Államok: teljesül, elutasított,vagy függőben. Az ígéret felhasználók visszahívásokat csatolhatnak a teljesített érték vagy az elutasítás okának kezelésére.

Az ígéretek buzgóak, ami azt jelenti, hogy egy ígéret elkezdi bármilyen feladatot elvégezni, amint az ígéret konstruktor meghívásra kerül. Ha lusta, nézd meg a megfigyeléseket vagy feladatokat.

az ígéretek hiányos története

az ígéretek és határidők korai implementációi (hasonló / kapcsolódó ötlet) már az 1980-as években megjelentek olyan nyelvekben, mint a MultiLisp és az egyidejű Prolog., Az “ígéret” szó használatát Barbara Liskov és Liuba Shrira alkotta meg 1988-ban.

amikor először hallottam a JavaScript-ben tett ígéretekről, a Node teljesen új volt, a közösség pedig az aszinkron viselkedés kezelésének legjobb módját tárgyalta. A közösség egy ideig kísérletezett ígéretekkel, de végül a csomóponton telepedett le-standard hiba-első visszahívások.

körülbelül ugyanabban az időben Dojo hozzáadott ígéreteket a halasztott API-n keresztül. A növekvő érdeklődés és aktivitás végül az újonnan kialakított ígéretekhez/specifikációhoz vezetett, amelynek célja a különböző ígéretek interoperábilisabbá tétele.,

jQuery async viselkedését az ígéretek körül refaktorálták. jQuery ígéretének támogatottsága figyelemre méltó hasonlóságot mutat Dojo Halasztásával, és jQuery óriási népszerűségének köszönhetően gyorsan a JavaScript leggyakrabban használt ígéretévé vált — egy ideig. Azonban nem támogatta a két csatorna (teljesített/elutasított) láncolás viselkedését & kivételkezelés, amelyre az emberek számítottak, hogy eszközöket építsenek az ígéretek tetejére.,

a gyengeségek ellenére jQuery hivatalosan JavaScript-ígéreteket tett a mainstreamben, és jobb önálló ígéretkönyvtárakat, mint például a Q, When, és a Bluebird nagyon népszerűvé vált. a jQuery implementációja néhány fontos pontosítást motivált a promise spec-ben, amelyet az ígéret/a+ specifikációnak megfelelően átírtak és átneveztek.,

az ES6 ígéreteket hozott/a+ kompatibilis Promise globális, és néhány nagyon fontos API-t építettek az új standard ígéret támogatására: nevezetesen a WHATWG Fetch spec és az Async funkciók szabványára (az írás idején a 3.szakasz tervezete).

az itt leírt ígéretek azok, amelyek kompatibilisek az ígéretek / A + specifikációval, az ECMAScript szabványra összpontosítva Promise végrehajtás.

How Promises Work

Az ígéret olyan objektum, amelyet szinkronban vissza lehet adni egy aszinkron függvényből., Ez lesz az egyik 3 lehetséges Államok:

egy ígéretet rendezni, ha ez nem függőben van (ez megoldódott, vagy elutasították). Néha az emberek a megoldott és rendezett, hogy ugyanazt jelenti: nem függőben.

miután rendezni, ígéret nem lehet áttelepíteni. A resolve() vagy reject() ismét nem lesz hatása. Az állandó ígéret megváltoztathatatlansága fontos jellemzője.

natív JavaScript ígéretek ne tegye ígéret Államok. Ehelyett elvárják, hogy az ígéretet fekete dobozként kezelje., Csak az ígéret létrehozásáért felelős funkció ismeri az ígéret állapotát, vagy hozzáférhet a megoldáshoz vagy elutasításhoz.

itt van egy függvény, amely visszatér egy ígéret, amely megoldja, miután egy meghatározott késleltetési idő:

várjon — ígéret példa CodePen

hívás vár 3000ms (3 másodperc), majd jelentkezzen 'Hello!'., Minden spec-kompatibilis ígéret definiál egy .then() módszert, amelyet a kezelők átadására használ, amely képes megoldani vagy elutasítani az értéket.

az ES6 promise konstruktor függvényt vesz fel. Ez a függvény két paramétert foglal magában: resolve()és reject(). A fenti példában csak a resolve() – ot használjuk, így a reject() – ot elhagytam a paraméterlistából. Ezután hívjuk asetTimeout() – t a késleltetés létrehozásához, majd hívjuk aresolve() – t, amikor elkészült.,

opcionálisanresolve() vagyreject() értékekkel, amelyeket átadnak a.then()csatolt visszahívási funkcióknak.

amikor ireject() értékkel mindig egy Error objektumot adok át. Általában két lehetséges felbontási állapotot akarok: a normál boldog utat, vagy kivételt-bármi, ami megakadályozza a normális boldog utat. A Error objektum átadása ezt explicitvé teszi.,

fontos ígéret szabályok

az ígéretek szabványát az ígéretek/a+ specifikációs közösség határozta meg. Sok megvalósítások, amelyek megfelelnek a szabványnak, beleértve a JavaScript szabvány ECMAScript ígér.

a specifikációt követő ígéreteknek egy meghatározott szabályrendszert kell követniük:

  • egy ígéret vagy “thenable” olyan objektum, amely szabványos .then() módszert biztosít.
  • egy függőben lévő ígéret teljesíthető vagy elutasított állapotba kerülhet.,
  • a teljesített vagy elutasított ígéret rendeződik, és nem léphet át más államba.
  • egy ígéret kiegyenlítése után egy értéknek kell lennie (amely lehet undefined). Ez az érték nem változhat.

a változás ebben az összefüggésben identitásra utal (===) összehasonlítás. Egy objektum használható teljesülési értékként, az objektum tulajdonságai pedig mutálódhatnak.,

minden ígéretnek meg kell adnia a.then() módszert a következő aláírással:

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

a.then() metódusnak meg kell felelnie ezeknek a szabályoknak:

  • mindkétonFulfilled() ésonRejected() választható.
  • ha a megadott argumentumok nem függvények, azokat figyelmen kívül kell hagyni.
  • onFulfilled() az ígéret teljesülése után kerül meghívásra, az ígéret értéke az első érv.,
  • onRejected() az ígéret elutasítása után hívják fel, az elutasítás oka az első érv. Ennek oka lehet bármilyen érvényes JavaScript érték, de mivel az elutasítások lényegében szinonimák a kivételekkel, javaslom a Hibaobjektumok használatát.
  • sem onFulfilled(), sem onRejected() nem nevezhető többször.
  • .then() ugyanazon ígéret szerint sokszor hívható. Más szavakkal, egy ígéret felhasználható a visszahívások összesítésére.,
  • .then() vissza kell adnia egy új ígéretet, promise2.
  • If onFulfilled() vagy onRejected() visszaad egy értéket x és x egy ígéret, promise2 a xértékkel záródik. Ellenkező esetben apromise2xértékkel teljesül.,
  • ha vagy onFulfilled vagy onRejected e, promise2 e mint az OK.
  • If onFulfillednem függvény, és promise1teljesül, promise2ugyanolyan értékkel kell teljesíteni, mint a promise1.,
  • Ha onRejected nem függvény, és promise1 elutasításra kerül, promise2 a promise1elutasításra kerül.

Promise Chaining

mert .then() mindig visszaad egy új ígéretet, lehetséges, hogy lánc ígéretek pontos ellenőrzése, hogyan és hol hibákat kezelik. Az ígéretek lehetővé teszik a normál szinkron kód try/ viselkedés utánzását.,

mint a szinkron kód, a láncolás soros sorozatot eredményez., Más szavakkal, ön tehet:

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

Itt egy példa a komplex ígéret lánc több elutasítás:

Ígéret egymás viselkedését, például a CodePen

Hiba-Kezelés

Megjegyezzük, hogy az ígéretek mind a siker, de egy hiba kezelő, ezért nagyon gyakori, hogy a kódot, hogy ez:

save().then(
handleSuccess,
handleError
);

De mi történik, ha a handleSuccess() dob hiba?, A .then() – tól visszaküldött ígéret elutasításra kerül, de nincs semmi, ami elkapná az elutasítást — ami azt jelenti, hogy az alkalmazás hibáját lenyelik. Hoppá!

ezért egyesek a fenti kódot anti-mintának tekintik, ehelyett a következőket ajánlják:

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

a különbség finom, de fontos. Az első példában a save() műveletből származó hiba fogható, de a handleSuccess() funkcióból származó hiba lenyelésre kerül.,

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., (diagram forrás)

természetesen a save() hiba lehet hálózati hiba, mivel a handleSuccess() hiba lehet, mert a fejlesztő elfelejtette kezelni egy adott állapotkódot. Mi van, ha másképp akarja kezelni őket? Mindkettőt kezelheti:

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

bármit is szeretne, azt javaslom, hogy az összes ígéretláncot egy .catch(). Ezt érdemes megismételni:

azt javaslom, hogy az összes ígéretláncot a .catch().,

hogyan törölhetek egy ígéretet?

az egyik első dolog, amit a new promise felhasználók gyakran csodálkoznak, hogy hogyan lehet visszavonni egy ígéretet. Íme egy ötlet: csak utasítsa el az ígéretet a “törölt” okként. Ha másképp kell kezelnie, mint egy “normál” hiba, akkor végezze el az elágazást a hibakezelőn.

Íme néhány gyakori hiba, amelyet az emberek követnek el, amikor saját ígéretüket visszavonják:

hozzátéve .,mégsem() az ígéret

hozzátéve .cancel() teszi az ígéret nem szabványos, de ez is sérti egy másik szabály az ígéretek: csak a funkció, amely létrehozza az ígéret képesnek kell lennie arra, hogy megoldja, elutasítja, vagy megszünteti az ígéretet. Kiteszik megszakad, hogy beágyazási, illetve arra ösztönzi az embereket, hogy kódot írni, hogy manipulálja az ígéret a helyen, hogy nem tud róla. Kerülje a spagettit és a megszegett ígéreteket.

elfelejtve, hogy tisztítsák meg

néhány okos ember rájött, hogy van egy módja annak, hogy a Promise.race() törlési mechanizmusként használja., Ezzel az a probléma, hogy a törlési vezérlés az ígéretet létrehozó funkcióból származik, amely az egyetlen hely, ahol megfelelő tisztítási tevékenységeket végezhet, például az időtúllépések törlése vagy a memória felszabadítása az adatokra való hivatkozások törlésével stb…

elfelejtette kezelni az elutasított mégsem ígéretet

tudta, hogy a Chrome figyelmeztető üzeneteket dob az egész konzolra, amikor elfelejtette kezelni az ígéret elutasítását? Hoppá!

a visszavont tc39 törlési javaslat külön üzenetküldő csatornát javasolt a törlések számára., Azt is használt egy új koncepció az úgynevezett lemondási token. Véleményem szerint a megoldás jelentősen felpuffasztotta volna az ígéretspekciót, és az egyetlen jellemzője, hogy a spekulációk közvetlenül nem támogatják az elutasítások és törlések szétválasztását, ami, IMO, először is, nem szükséges.

szeretne váltani attól függően, hogy van-e kivétel vagy törlés? Igen, teljesen. Ez az ígéret dolga? Véleményem szerint nem, nem az.,

az ígéret visszavonásának újragondolása

általában minden olyan információt átadok, amelyre az ígéretnek szüksége van annak meghatározásához, hogyan kell megoldani / elutasítani / törölni az ígéret létrehozásakor. Így nincs szükség egy .cancel() módszerre egy ígéretnél. Lehet, hogy kíváncsi, hogyan lehet esetleg tudni, hogy vagy nem fogsz lemondani a promise creation idő.

” Ha még nem tudom, hogy törölni kell-e vagy sem, Hogyan tudom, mit kell átadni, amikor létrehozom az ígéretet?,”

Ha csak lenne valamilyen tárgy, amely a jövőben potenciális értéket jelenthet … Oh, várj.

az érték, amelyet átadunk, hogy képviseljük, hogy a lemondás önmagában ígéret lehet-e vagy sem. Így nézhet ki:

Cancellable wait — próbálja ki a codepen

alapértelmezett paraméter hozzárendelést használunk, hogy megmondjuk, hogy alapértelmezés szerint ne törölje. Így a cancel paraméter kényelmesen választható., Ezután beállítjuk az időtúllépést, mint korábban, de ezúttal rögzítjük az időtúllépés Azonosítóját, hogy később törölhessük.

a cancel.then() módszert használjuk a törlés és az erőforrás-Tisztítás kezelésére. Ez csak akkor fog működni, ha az ígéret visszavonásra kerül, mielőtt esélye lenne megoldani. Ha túl későn mondod le, elszalasztottad a lehetőséget. A vonat elhagyta az állomást.

Megjegyzés: lehet, hogy kíváncsi, hogy mi a noop() funkció. A szó noop jelentése no-op, ami azt jelenti, egy funkció, amely nem csinál semmit., Anélkül, hogy a V8 figyelmeztetéseket dobna: UnhandledPromiseRejectionWarning: Unhandled promise rejection. Ez egy jó ötlet, hogy mindig kezelni ígéret elutasítások, akkor is, ha a kezelő egy noop().

Referáló Ígéret Törlés

Ez rendben van egy wait() időzítő, de absztrakt ez a gondolat tovább, hogy magukba mindent meg kell emlékezni:

  1. Elutasítja a cancel ígéret alapértelmezés szerint — nem akarjuk, hogy megszünteti vagy dobja hiba, ha nem, mégse ígéretet kap telt el.
  2. ne felejtse el elvégezni a tisztítást, amikor elutasítja a törléseket.,
  3. ne feledje, hogy a onCancel razzia maga is hibát okozhat, és ezt a hibát is kezelni kell. (Vegye figyelembe, hogy a fenti várakozási példában a hibakezelés elmarad — könnyű elfelejteni!)

hozzunk létre egy lemondható ígéret segédprogramot, amellyel bármilyen ígéretet be lehet csomagolni., Például, hogy kezelni a hálózati kéréseket, stb… Az aláírás fog kinézni:

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

A SpecFunction, mint a funkció át a Promise kivitelező, egy kivétellel — csak egy onCancel() kezelő:

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

Megjegyezzük, hogy ez a példa csak illusztráció adni, a lényeg, hogy működik. Vannak más él esetek, amelyeket figyelembe kell venni., Például ebben a verzióban ahandleCancel meghívásra kerül, ha az ígéretet a már rendezett állapot után visszavonja.

ennek egy karbantartott gyártási verzióját implementáltam, az edge tokokkal, mint a nyílt forráskódú könyvtár, spekuláció.

használjuk a javított könyvtár absztrakcióját a visszavonható wait() segédprogram átírásához., Először telepíteni spekuláció:

npm install --save speculation

Most importálni használni:

Ez leegyszerűsíti a dolgokat egy kicsit, mert nem kell aggódnia, hogy a noop(), felzárkózás hibák a onCancel(), funkció vagy más szélén esetekben. Ezeket a részleteket a speculation()absztrahálta. Nézd meg, és nyugodtan használja azt a valós projektek.,

extrák a natív js ígéret

a natív Promise objektum van néhány extra dolog, amit lehet, hogy érdekel:

  • Promise.reject() visszaadja az elutasított ígéretet.
  • Promise.resolve() egy megoldott ígéretet ad vissza.
  • Promise.race() vesz egy tömb (vagy bármilyen iterable), és visszatér egy ígéretet, hogy megoldja az értéke az első megoldott ígéret az iterable, vagy elutasítja az oka az első ígéret, hogy elutasítja.,
  • Promise.all() vesz egy tömb (vagy bármilyen iterable) és visszatér egy ígéretet, hogy megoldja, ha az ígéretek az iterable érv megoldódott, vagy elutasítja az oka az első elfogadott ígéret, hogy elutasítja.

következtetés

Az ígéretek a JavaScript számos idiómájának szerves részévé váltak, beleértve a legmodernebb ajax kérésekhez használt WHATWG Fetch szabványt,valamint az aszinkron kód szinkronizálásához használt Async funkciók szabványt.,

az Async funkciók az írás idején a 3. szakasz, de azt jósolom, hogy hamarosan nagyon népszerű, nagyon általánosan használt megoldássá válnak az aszinkron programozáshoz a JavaScriptben — ami azt jelenti, hogy az ígéretek értékelésének megtanulása a közeljövőben még fontosabb lesz a JavaScript fejlesztők számára.

például, ha Redux-ot használ, azt javaslom, hogy nézze meg a redux-saga: A Redux mellékhatásainak kezelésére használt könyvtárat, amely az async funkcióktól függ a dokumentációban.,

remélem, hogy még a tapasztalt ígéretek is jobban megértik, hogy Milyen ígéretek vannak, hogyan működnek, és hogyan lehet ezeket jobban használni, miután elolvasta ezt.

fedezze fel a sorozatot

  • mi a lezárás?
  • mi a különbség az osztály és a prototípus öröklés között?
  • mi a tiszta funkció?
  • mi a Függvényösszetétel?
  • mi a funkcionális programozás?
  • mi az ígéret?
  • Soft Skills

Vélemény, hozzászólás?

Az email címet nem tesszük közzé. A kötelező mezőket * karakterrel jelöltük