„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í:
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()
anionRejected()
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()
neboonRejected()
vrátit hodnotux
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ě budepromise2
splněna hodnotax
., - Pokud ani
onFulfilled
neboonRejected
vyvolá výjimkue
promise2
musí být zamítnut se
jako důvod. - Pokud
onFulfilled
je funkcepromise1
je splněna,promise2
musí být splněny se stejnou hodnotou jakopromise1
., - Pokud
onRejected
je funkcepromise1
je zamítnuta,promise2
musí být odmítl se stejným důvodem jakopromise1
.
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í:
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()
.,
In the second example, .catch()
will handle rejections from either save()
, or handleSuccess()
.
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:
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:
- 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.
- nezapomeňte provést vyčištění, když odmítnete zrušení.,
- 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