Eric Elliott

Sledovat

Jan 23, 2017 · 11 min číst

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

„Mistr JavaScript Rozhovor“ je řada míst, navržen tak, aby připravit kandidáty na nejčastější otázky, se kterými se pravděpodobně setkáte při žádosti o střední vyšší úrovni-JavaScript pozice. To jsou otázky, které často používám v reálných rozhovorech.

slib je objekt, který může produkovat jednu hodnotu nějaký čas v budoucnosti: buď vyřešeny hodnotu, nebo důvod, že to není vyřešen (např. došlo k chybě sítě)., Slib může být v jednom ze 3 možných států: splněn, zamítnut, nebo čeká. Slib uživatelé mohou připojit zpětné volání zvládnout splněnou hodnotu nebo důvod odmítnutí.

sliby jsou dychtivé, což znamená, že slib začne dělat jakýkoli úkol, který mu dáte, jakmile bude vyvolán Konstruktor slibů. Pokud potřebujete líný, podívejte se na pozorovatelné nebo úkoly.

Nekompletní Historie Sliby

na Začátku implementace sliby a futures (podobné / související idea) se začaly objevovat v jazycích, jako je MultiLisp a Souběžné Prolog jak již v roce 1980., Použití slova „slib“ vytvořili Barbara Liskov a Liuba Shrira v roce 1988.

Když jsem poprvé slyšel o slibech v JavaScriptu, uzel byl zcela nový a komunita diskutovala o nejlepším způsobu, jak zvládnout asynchronní chování. Komunita chvíli experimentovala se sliby, ale nakonec se usadila na uzlu-standardní chyba-první zpětné volání.

přibližně ve stejnou dobu přidalo Dojo sliby prostřednictvím odloženého API. Rostoucí zájem a aktivita nakonec vedla k nově vytvořené Sliby/specifikace navržen tak, aby různé sliby více interoperabilní.,

jqueryho chování async bylo refaktorováno kolem slibů. jQuery je slib podporu měl pozoruhodné podobnosti s Dojo je Odložené, a to rychle se stal nejvíce běžně používané slib implementace v Javascriptu díky jQuery je obrovskou popularitu — na chvíli. Nicméně, to není podpora dvou kanálů (splnil/zamítnuta) řetězení chování & výjimkou řízení, že lidé počítali stavět nástroje na vrcholu sliby.,

navzdory těmto slabostem jQuery oficiálně učinil JavaScript sliby hlavního proudu a lepší samostatné slibné knihovny jako Q, kdy a Bluebird se staly velmi populárními. jQuery je realizace motivované nesnášenlivosti některé důležité vysvětlení slib spec, který byl přepsán a rebranded jako Slibuje/A+ specifikace.,

ES6 přinesl Slibuje/A+ kompatibilní Promise globální, a některé velmi důležité Api byly postaveny na vrcholu nový standard Slib podpory: zejména WHATWG Načíst spec a Asynchronní Funkce standardní (fáze 3 návrh v době psaní tohoto článku).

zde popsané sliby jsou ty, které jsou kompatibilní se specifikací Promises/a+ se zaměřením na standard ECMAScript Promise implementace.

jak sliby fungují

slib je objekt, který lze synchronně vrátit z asynchronní funkce., Bude to v jednom ze 3 možných stavů:

slib je vypořádán, pokud není čekající (byl vyřešen nebo zamítnut). Někdy lidé používají vyřešeno a usadil se znamenat totéž: nevyřízené.

po vypořádání nelze slib přesídlit. Volání resolve() nebo reject() opět nebude mít žádný účinek. Neměnnost ustáleného slibu je důležitou vlastností.

nativní JavaScript sliby nevystavují slibné stavy. Místo toho se očekává, že budete tento slib považovat za černou skříňku., Pouze funkce odpovědná za vytvoření slibu bude mít znalost stavu slibu nebo přístup k vyřešení nebo odmítnutí.

Tady je funkce, která vrací slib, který zmizí po určité časové zpoždění:

počkejte — slib, že například na CodePen

Naše wait(3000) hovor bude čekat 3000ms (3 sekundy), a pak se přihlaste 'Hello!'., Všechny sliby kompatibilní s spec definují metodu .then(), kterou používáte k předávání manipulátorů, které mohou mít vyřešenou nebo odmítnutou hodnotu.

Konstruktor ES6 promise má funkci. Tato funkce má dva parametry, resolve() a reject(). Ve výše uvedeném příkladu používáme pouze resolve(), takže jsem opustil reject() ze seznamu parametrů. Poté zavolámesetTimeout() pro vytvoření zpoždění a po dokončení zavoláme resolve().,

volitelně můžete resolve() nebo reject() s hodnotami, které bude předán do funkce zpětného volání připojeny pomocí .then().

když reject() s hodnotou, vždy předávámError objekt. Obecně chci dva možné stavy rozlišení: normální šťastná cesta, nebo výjimka — cokoli, co zastaví normální šťastnou cestu od děje. AbsolvováníError objekt dělá to explicitní.,

důležitá Slibová pravidla

standard pro sliby byl definován komunitou Promises/a+ specification. Existuje mnoho implementací, které odpovídají standardu, včetně slibů standardu JavaScript ECMAScript.

Sliby následující spec musí dodržovat určitá pravidla:

  • slib, nebo „thenable“ je objekt, který poskytuje standardní kompatibilní .then() metoda.
  • čekající příslib může přejít do splněného nebo odmítnutého stavu.,
  • splněný nebo odmítnutý slib je urovnán a nesmí přecházet do žádného jiného státu.
  • jakmile je slib vypořádán, musí mít hodnotu (která může být undefined). Tato hodnota se nesmí měnit.

změna v tomto kontextu se týká porovnání identity (). Objekt může být použit jako splněná hodnota a vlastnosti objektu mohou mutovat.,

Každý slib musíte zadat .then() metoda s následující podpis:

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

.then() metoda musí být v souladu s těmito pravidly:

  • onFulfilled() onRejected() jsou volitelné.
  • pokud zadané argumenty nejsou funkce, musí být ignorovány.
  • onFulfilled() bude volán po splnění slibu, s hodnotou slibu jako první argument.,
  • onRejected() bude volán po odmítnutí slibu, s důvodem odmítnutí jako prvního argumentu. Důvodem může být jakákoli platná hodnota JavaScriptu, ale protože odmítnutí jsou v podstatě synonymem výjimek, doporučuji použít chybové objekty.
  • ani onFulfilled()ani onRejected() lze volat více než jednou.
  • .then() lze volat mnohokrát na stejném slibu. Jinými slovy, slib lze použít k agregaci zpětné volání.,
  • .then() musí vrátit nový slib, promise2.
  • Pokud onFulfilled() nebo onRejected() vrátit hodnotu x x je slib, promise2 bude zámek v s (předpokládám stejný stav a hodnotu jako) x. V opačném případě bude promise2 splněna hodnota x.,
  • Pokud ani onFulfilled nebo onRejected vyvolá výjimku e promise2 musí být zamítnut s e jako důvod.
  • Pokud onFulfilled je funkce promise1 je splněna, promise2 musí být splněny se stejnou hodnotou jako promise1.,
  • Pokud onRejected je funkce promise1 je zamítnuta, promise2 musí být odmítl se stejným důvodem jako promise1.

Slib Řetězení

, Protože .then(), vždy vrací nový promise, je možné, aby řetězec slibuje s přesnou kontrolu nad tím, jak a kde chyby jsou řešeny. Sliby vám umožní napodobit normální synchronní kód try/catch chování.,

jako synchronní kód, řetězení bude mít za následek sekvenci, která běží v sériovém., Jinými slovy, můžete to udělat:

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

Zde je příklad komplexní slib řetězce s více odmítnutí:

Slib řetězení chování, například na CodePen

Chyba při Zpracování

Všimněte si, že sliby, které mají úspěch a error handler, a to je velmi běžné vidět kód, který dělá toto:

save().then(
handleSuccess,
handleError
);

Ale co se stane, když handleSuccess() hodí chybu?, Slib, který se vrátil z .then() budou zamítnuty, ale nic tam není chytit odmítnutí — což znamená, že chyba ve vaší aplikaci dostane požití. Jejda!

z tohoto důvodu, někteří lidé považují výše uvedený kód musí být anti-vzor, a doporučit následující, místo:

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

rozdíl je jemné, ale důležité. V prvním příkladu bude zachycena chyba pocházející z operace save(), ale dojde k chybě pocházející z funkce handleSuccess().,

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 zdroj)

samozřejmě, save() chyba může být networking chyba, vzhledem k tomu, že handleSuccess() chyba může být, protože developer zapomněl zpracovat konkrétní stavový kód. Co když s nimi chcete zacházet jinak? Můžete se rozhodnout, jak s nimi zacházet:

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

ať už dáváte přednost, doporučuji ukončit všechny slibné řetězce pomocí .catch(). To stojí za to opakovat:

doporučuji ukončit všechny slibné řetězce .catch().,

Jak mohu zrušit slib?

jednou z prvních věcí, o kterých se uživatelé nových slibů často ptají, je, jak zrušit slib. Tady je nápad: prostě odmítnout slib s“ zrušeno “ jako důvod. Pokud se s tím musíte vypořádat jinak než s“ normální “ chybou, proveďte větvení ve svém manipulátoru chyb.

zde jsou některé běžné chyby, které lidé dělají, když hodí své vlastní zrušení slibu:

přidání.,zrušit() příslib

Přidání .cancel() dává příslib non-standard, ale také porušuje další pravidlo slibů: Pouze funkce, která vytváří slib by měl být schopen vyřešit, odmítnout, nebo zrušit slib. Odhalení to rozbije toto zapouzdření, a povzbuzuje lidi, aby psali kód, který manipuluje s příslibem na místech, která by o tom neměla vědět. Vyhněte se špagetám a zlomeným slibům.

Zapomněl uklidit

Někteří chytří lidé zjistili, že existuje způsob, jak použít Promise.race() jako storno mechanismus., Problém s tímto je, že zrušení kontroly je převzat z funkce, která vytváří slib, což je jediné místo, kde můžete provést řádné vyčištění činností, jako jsou clearing časové limity nebo uvolnění paměti tím, že odstraní odkazy na data, atd…

Zapomněli jste zvládnout odmítnutý slib zrušení

věděli jste, že Chrome hází varovné zprávy po celé konzoli, když zapomenete zvládnout odmítnutí slibu? Jejda!

příliš složité

stažený návrh tc39 na zrušení navrhl samostatný kanál pro zasílání zpráv pro zrušení., Použil také nový koncept nazvaný Storno token. Podle mého názoru, řešením by mohlo mít značně nafouklé slib spec, a jediná funkce, to by za předpokladu, že spekulace ne přímo podporovat je oddělení odmítnutí a zrušení, což IMO není třeba začínat.

budete chtít provést přepínání v závislosti na tom, zda existuje výjimka nebo zrušení? Ano, rozhodně. To je práce slibu? Podle mého názoru ne, není.,

přehodnocení slibu zrušení

obecně předávám všechny informace, které slib potřebuje k určení, jak vyřešit / odmítnout / zrušit v době vytvoření slibu. Tímto způsobem není potřeba .cancel() metoda na slib. Možná vás zajímá, jak byste mohli vědět, zda se chystáte zrušit v době vytvoření slibu.

“ Pokud ještě nevím, zda zrušit, jak budu vědět, co předat, když vytvořím slib?,“

kdyby existoval nějaký objekt, který by mohl v budoucnu stát za potenciální hodnotou… Oh, počkej.

hodnota, kterou předáváme, aby reprezentovala, zda zrušení může být slib sám. Zde je návod, jak to může vypadat:

Zrušit čekat — zkuste to na CodePen

Jsme pomocí výchozí parametr úkol řekněte, není zrušit ve výchozím nastavení. Díky tomu je parametr cancel pohodlně volitelný., Pak jsme nastavili časový limit jako předtím, ale tentokrát zachytíme časový limit, abychom jej mohli později vyčistit.

pro zpracování zrušení a vyčištění zdrojů používáme metoducancel.then(). To bude fungovat pouze v případě, že slib bude zrušen dříve, než bude mít šanci vyřešit. Pokud zrušíte příliš pozdě, jste vynechal svou šanci. Ten vlak opustil nádraží.

Poznámka: možná se divíte, pro co je funkce noop() určena. Slovo noop znamená ne-op, což znamená funkci, která nic nedělá., Bez něj bude V8 házet varování: UnhandledPromiseRejectionWarning: Unhandled promise rejection. Je to dobrý nápad, aby vždy zvládnout slib odmítnutí, i když váš psovod je .

Abstrahovat Slib Zrušení

Tohle je v pořádku na wait() časovač, ale můžeme abstraktní tuto myšlenku dále zapouzdřit vše, co musíte mít na paměti:

  1. Odmítnout zrušit slib, že ve výchozím nastavení — nechceme zrušit, nebo házet chyby, pokud ne zrušit slib, že dostane předány.
  2. nezapomeňte provést vyčištění, když odmítnete zrušení.,
  3. nezapomeňte, že vyčištěníonCancel může samo o sobě způsobit chybu a tato chyba bude také potřebovat manipulaci. (Všimněte si, že manipulace s chybami je vynechána ve výše uvedeném příkladu čekání – je snadné zapomenout!)

vytvoříme nástroj pro zrušení slibu, který můžete použít k zabalení jakéhokoli slibu., Například, zvládnout požadavky sítě, atd…. podpis bude vypadat takto:

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

SpecFunction je stejně jako funkci, kterou by projít do Promise konstruktoru, s jednou výjimkou — trvá onCancel() handler:

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

Všimněte si, že tento příklad je pouze ilustrační, aby vám ukázat podstatu toho, jak to funguje. Existují některé další okrajové případy, které je třeba vzít v úvahu., Například v této verzi bude voláno handleCancel, pokud zrušíte slib poté, co je již vypořádán.

implementoval jsem udržovanou produkční verzi s případy edge, které jsou pokryty jako knihovna s otevřeným zdrojovým kódem, spekulace.

použijeme vylepšenou abstrakci knihovny k přepsání zrušeného nástroje wait() z dřívějška., Nejprve nainstalovat spekulace:

npm install --save speculation

Nyní můžete importovat a použít je:

To zjednodušuje věci trochu, proto, nemusíte se starat o noop(), chytání chyb v onCancel(), funkce nebo jiné okraj případech. Tyto detaily byly abstrahovány speculation(). Podívejte se na to a neváhejte jej použít v reálných projektech.,

Extra Nativní JS Slib

nativní Promise objekt má některé věci navíc by tě mohl zajímat:

  • Promise.reject() vrací odmítl slib.
  • Promise.resolve() vrací vyřešený slib.
  • Promise.race() bere pole (nebo jakýkoliv iterable) a vrátí slib, že řeší s hodnotou první vyřešen slib v iterable, nebo zamítne s důvodem, proč první slib, že odmítne.,
  • Promise.all() bere pole (nebo jakýkoliv iterable) a vrátí slíbit, že se řeší, když všechny sliby v iterable argument vyřešen, nebo zamítne s důvodem, proč první složil slib, že odmítne.

Závěr

Sliby se staly nedílnou součástí několika idiomů v jazyce JavaScript, včetně WHATWG Načíst standard používaný pro většinu moderních ajaxových požadavků, a Asynchronní Funkce standard se používá, aby se asynchronní kód pohled synchronní.,

Async funkce jsou fáze 3 v době psaní tohoto článku, ale předpokládám, že se brzy stala velmi populární, velmi často používané řešení pro asynchronní programování v JavaScript — což znamená, že naučit se ocenit slibuje, že bude ještě více důležité, aby JavaScript vývojářů v blízké budoucnosti.

například, pokud používáte Redux, domnívám se, že vás podívejte se na redux-saga: knihovna používá pro správu vedlejší účinky v Redux, která závisí na asynchronní funkce v celé dokumentaci.,

doufám, že i zkušení uživatelé promise mají lepší pochopení toho, co sliby jsou a jak fungují, a jak je lépe používat po přečtení.

Prozkoumejte sérii

  • co je to Uzavření?
  • jaký je rozdíl mezi třídou a prototypovou dědičností?
  • co je to čistá funkce?
  • co je složení funkce?
  • co je funkční programování?
  • co je slib?
  • Soft Skills

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *