Eric Elliott

Volgen

Jan 23, 2017 · 11 min lezen

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

” Master the JavaScript Interview ” is een reeks posten die bedoeld zijn om kandidaten voor te bereiden op veelvoorkomende vragen die ze waarschijnlijk zullen tegenkomen bij het solliciteren naar een JavaScript-functie op mid-tot senior niveau. Dit zijn vragen die ik vaak gebruik in echte interviews.

een belofte is een object dat in de toekomst een enkele waarde kan produceren: ofwel een opgeloste waarde, ofwel een reden dat het niet is opgelost (Er is bijvoorbeeld een netwerkfout opgetreden)., Een belofte kan in een van de 3 mogelijke Staten: vervuld, afgewezen, of hangende. Promise-gebruikers kunnen callbacks toevoegen om de vervulde waarde of de reden voor afwijzing af te handelen.

Promises staan te popelen, wat betekent dat een promise elke taak zal uitvoeren die je hem geeft zodra de promise-constructor wordt aangeroepen. Als je luie nodig hebt, check out observables of taken.

een onvolledige geschiedenis van Beloften

vroege implementaties van beloften en futures (een soortgelijk / gerelateerd idee) begon al in de jaren tachtig te verschijnen in talen zoals MultiLisp en gelijktijdige Prolog., Het gebruik van het woord “belofte” werd bedacht door Barbara Liskov en Liuba Shrira in 1988.

De eerste keer dat ik hoorde over beloften in JavaScript, was Node gloednieuw en de gemeenschap besprak de beste manier om asynchrone gedrag te behandelen. De gemeenschap experimenteerde met beloften voor een tijdje, maar uiteindelijk geregeld op het knooppunt-standaard fout-eerste callbacks.

rond dezelfde tijd voegde Dojo Beloften toe via de uitgestelde API. De groeiende belangstelling en activiteit leidden uiteindelijk tot de nieuw gevormde Promises / a-specificatie die was ontworpen om verschillende Beloften beter interoperabel te maken.,

jQuery ‘ s Async-gedrag werd omgebogen rond Beloften. jQuery ’s promise ondersteuning had opmerkelijke overeenkomsten met dojo’ s uitgesteld, en het werd al snel de meest gebruikte promise implementatie in JavaScript als gevolg van jQuery ‘ s immense populariteit — voor een tijd. Het ondersteunde echter niet het tweekanaals (voldaan/afgewezen) chaining gedrag & exception management waarop mensen rekenden om tools te bouwen bovenop Beloften.,

ondanks deze zwakke punten, jQuery officieel gemaakt Javascript Beloften mainstream, en betere stand-alone belofte bibliotheken zoals Q, When, En Bluebird werd erg populair. jQuery ‘ s implementatie onverenigbaarheden motiveerde een aantal belangrijke verduidelijkingen in de promise spec, die werd herschreven en omgedoopt tot de Promises/A+ specificatie.,

ES6 bracht een Promises/A+ compliant Promise globaal, en enkele zeer belangrijke API ‘ s werden gebouwd bovenop de nieuwe standaard Promise ondersteuning: met name de WHATWG Fetch spec en de Async Functions standard (een fase 3 ontwerp op het moment van dit schrijven).

De hier beschreven beloften zijn die welke compatibel zijn met de Promises/A+ specificatie, met een focus op de ECMAScript standaard Promise implementatie.

hoe beloftes werken

een belofte is een object dat synchroon kan worden geretourneerd vanuit een asynchrone functie., Het zal in een van de 3 mogelijke toestanden zijn:

een belofte wordt afgewikkeld als het niet in behandeling is (het is opgelost of afgewezen). Soms gebruiken mensen resolved en settled om hetzelfde te betekenen: niet in behandeling.

eenmaal afgewikkeld, kan een belofte niet worden hervestigd. Het opnieuw aanroepen van resolve() of reject() heeft geen effect. De onveranderlijkheid van een vaste belofte is een belangrijk kenmerk.

Native JavaScript promises tonen geen promise statussen. In plaats daarvan moet je de belofte behandelen als een zwarte doos., Alleen de functie die verantwoordelijk is voor het creëren van de belofte zal kennis hebben van de status van de belofte, of toegang hebben om op te lossen of af te wijzen.

Hier is een functie die een belofte retourneert die zal oplossen na een opgegeven tijdsvertraging:

wait — promise voorbeeld op CodePen

onzewait(3000)aanroep zal 3000ms (3 seconden) wachten en vervolgens'Hello!'loggen., Alle Spec-compatibele Beloften definiëren een.then() methode die u gebruikt om handlers te passeren die de gevonden of afgewezen waarde kunnen nemen.

De ES6 promise constructor heeft een functie. Deze functie heeft twee parameters, resolve(), en reject(). In het voorbeeld hierboven gebruiken we alleen resolve(), dus heb ik reject() uit de parameterlijst gelaten. Daarna roepen we setTimeout() aan om de vertraging aan te maken, en roepen we resolve() aan als het klaar is.,

u kunt optioneel resolve() of reject() met waarden geven, die worden doorgegeven aan de callback functies die verbonden zijn met .then().

wanneer i reject() met een waarde, geef ik altijd een Error object. Over het algemeen wil ik twee mogelijke resolutietoestanden: het normale gelukkige pad, of een uitzondering — alles wat het normale gelukkige pad tegenhoudt. Het doorgeven van een Error object maakt dat expliciet.,

belangrijke Promise regels

een standaard voor promises werd gedefinieerd door de Promises / A+ specificatie gemeenschap. Er zijn veel implementaties die voldoen aan de standaard, met inbegrip van de JavaScript standaard ECMAScript Beloften.

beloften die de specificatie volgen, moeten een specifieke set regels volgen:

  • een belofte of “thenable” is een object dat een standaard-compatibele .then() methode levert.
  • een in behandeling zijnde belofte kan overgaan in een vervulde of afgewezen toestand.,
  • een vervulde of geweigerde belofte wordt afgewikkeld, en mag niet naar een andere staat overgaan.
  • zodra een belofte is afgewikkeld, moet deze een waarde hebben (die undefinedkan zijn). Die waarde mag niet veranderen.

verandering in deze context verwijst naar identiteit (===) vergelijking. Een object kan worden gebruikt als de vervulde waarde, en objecteigenschappen kunnen muteren.,

Every promise must supply a .then() method with the following signature:

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

The .then() method must comply with the these rules:

  • Both onFulfilled() en onRejected() zijn optioneel.
  • als de opgegeven argumenten geen functies zijn, moeten ze genegeerd worden.
  • onFulfilled() wordt aangeroepen nadat de belofte is vervuld, met de waarde van de belofte als eerste argument.,
  • onRejected() wordt aangeroepen nadat de belofte is afgewezen, met als eerste argument de reden voor de afwijzing. De reden kan een geldige JavaScript waarde, maar omdat afwijzingen zijn in wezen synoniem met uitzonderingen, ik raad het gebruik van fout objecten.
  • noch onFulfilled() noch onRejected() mag meer dan één keer worden aangeroepen.
  • .then() kan vele malen worden aangeroepen op dezelfde belofte. Met andere woorden, een belofte kan worden gebruikt om callbacks samen te voegen.,
  • .then() moet een nieuwe belofte retourneren, promise2.
  • als onFulfilled() of onRejected() een waarde x retourneert en x een belofte is, zal promise2 vergrendelen met (neem aan dezelfde status en waarde als) x. Anders wordt aan promise2 voldaan met de waarde van x.,
  • als onFulfilled of onRejected een uitzondering geeft e, moet promise2 worden afgewezen met e als reden.
  • indien onFulfilled geen functie is en promise1 is vervuld, moet promise2 worden vervuld met dezelfde waarde als promise1.,
  • indien onRejected geen functie is en promise1 wordt afgewezen, moet promise2 worden afgewezen om dezelfde reden als promise1.

Promise Chaining

omdat .then() altijd een nieuwe belofte retourneert, is het mogelijk om Beloften te ketenen met nauwkeurige controle over hoe en waar fouten worden behandeld. Met Promises kunt u het gedrag van try/catch nabootsen.,

net als synchrone code, zal chaining resulteren in een reeks die in serieel draait., In andere woorden, je kunt doen:

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

Hier is een voorbeeld van een complexe belofte keten met meerdere afwijzingen:

Belofte chaining gedrag bijvoorbeeld op CodePen

Fout Afhandeling

Merk op dat belooft hebben zowel een succes als een fout van de handler, en het is heel gebruikelijk om te zien de code die dit doet:

save().then(
handleSuccess,
handleError
);

Maar wat gebeurt er als handleSuccess() gooit een foutmelding?, De belofte van .then() zal worden afgewezen, maar er is niets om de afwijzing te vangen — wat betekent dat een fout in uw app wordt ingeslikt. Oeps!

daarom beschouwen sommige mensen de bovenstaande code als een anti-patroon, en bevelen in plaats daarvan het volgende aan:

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

het verschil is subtiel, maar belangrijk. In het eerste voorbeeld zal een fout uit de functie save() worden opgevangen, maar een fout uit de functie handleSuccess() worden doorgeslikt.,

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., (diagrambron)

natuurlijk kan de save() fout een netwerkfout zijn, terwijl de handleSuccess() fout kan zijn omdat de ontwikkelaar vergat een specifieke statuscode af te handelen. Wat als je ze anders wilt aanpakken? U kunt ervoor kiezen om ze allebei af te handelen:

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

wat u ook verkiest, ik raad aan om alle belofte ketens te beëindigen met een .catch(). Dat is het herhalen waard:

Ik adviseer om alle belofte ketens te beëindigen met een .catch().,

Hoe annuleer ik een belofte?

een van de eerste dingen waar nieuwe promise-gebruikers zich vaak over afvragen is hoe ze een belofte kunnen annuleren. Hier is een idee: verwerp de belofte met “geannuleerd” als de reden. Als je nodig hebt om te gaan met het anders dan een “normale” fout, doe je vertakking in uw fout handler.

Hier zijn enkele veel voorkomende fouten die mensen maken wanneer ze hun eigen belofte annuleren:

toevoegen .,cancel () aan de belofte

Het toevoegen van .cancel() maakt de belofte niet-standaard, maar het schendt ook een andere regel van Beloften: alleen de functie die de belofte maakt moet in staat zijn om de belofte op te lossen, af te wijzen of te annuleren. Het blootstellen breekt die inkapseling, en moedigt mensen aan om code te schrijven die de belofte manipuleert op plaatsen die er niet van zouden moeten weten. Vermijd spaghetti en gebroken beloften.

vergeten op te ruimen

sommige slimme mensen hebben ontdekt dat er een manier is om Promise.race() als een annuleringsmechanisme te gebruiken., Het probleem daarmee is dat de annuleringscontrole wordt overgenomen van de functie die de belofte creëert, wat de enige plek is waar je goede opschoonactiviteiten kunt uitvoeren, zoals het wissen van timeouts of het vrijmaken van geheugen door verwijzingen naar gegevens te wissen, enz…

vergeten een geweigerde annuleringsbelofte af te handelen

Wist u dat Chrome waarschuwingsberichten over de hele console gooit wanneer u een afstoting van een belofte vergeet af te handelen? Oeps!

te complex

Het ingetrokken tc39-annuleringsvoorstel stelde een apart berichtenkanaal voor annuleringen voor., Het gebruikte ook een nieuw concept genaamd een annuleringstoken. Naar mijn mening, de oplossing zou aanzienlijk opgeblazen de belofte spec, en de enige functie die het zou hebben gesteld dat speculaties niet direct ondersteunen is de scheiding van afwijzingen en annuleringen, die, IMO, is niet nodig om te beginnen met.

wilt u wisselen afhankelijk van of er een uitzondering of een annulering is? Ja, absoluut. Is dat het werk van de belofte? Naar mijn mening, nee, dat is het niet.,

herdenken van belofte annulering

over het algemeen geef ik alle informatie door die de belofte nodig heeft om te bepalen hoe de belofte moet worden opgelost / afgewezen / geannuleerd tijdens het aanmaken van de belofte. Op die manier is er geen .cancel() methode nodig op een belofte. Je vraagt je misschien af hoe je zou kunnen weten of je gaat annuleren bij belofte creatie tijd.

” als ik nog niet weet of ik moet annuleren, hoe Weet ik dan wat ik moet doorgeven als ik de belofte maak?,”

was er maar een object dat in de toekomst een potentiële waarde zou kunnen hebben… oh, wacht.

de waarde die we doorgeven om aan te geven of annuleren wel of niet een belofte zelf kan zijn. Zo zou dat eruit kunnen zien:

Annuleerbare wacht — probeer het op CodePen

we gebruiken standaardparametertoewijzing om aan te geven dat het niet standaard moet annuleren. Dat maakt de parameter cancel gemakshalve optioneel., Dan stellen we de timeout in zoals we eerder deden, maar deze keer vangen we het ID van de timeout op zodat we het later kunnen wissen.

we gebruiken de methode cancel.then() om de annulering en bronopruiming af te handelen. Dit wordt alleen uitgevoerd als de belofte wordt geannuleerd voordat het een kans heeft om op te lossen. Als je te laat annuleert, heb je je kans gemist. Die trein heeft het station verlaten.

opmerking: u vraagt zich misschien af waar de functie noop() voor is. Het woord noop staat voor no-op, wat een functie betekent die niets doet., Zonder dit, zal V8 waarschuwingen gooien: UnhandledPromiseRejectionWarning: Unhandled promise rejection. Het is een goed idee om altijd promise afwijzingen af te handelen, zelfs als je handler een noop()is.

Abstracting Promise Cancellation

Dit is prima voor een wait() timer, maar we kunnen dit idee verder samenvatten om alles wat je moet onthouden in te kapselen:

  1. weiger de annuleringsbelofte standaard — we willen geen fouten annuleren of weggooien als er geen annuleringsbelofte wordt doorgegeven.
  2. vergeet niet op te schonen wanneer u weigert voor annuleringen.,
  3. onthoud dat deonCancel opschonen zelf een fout kan veroorzaken, en die fout moet ook behandeld worden. (Merk op dat error handling is weggelaten in het wacht voorbeeld hierboven-het is gemakkelijk te vergeten!)

laten we een annuleerbare promise utility maken die je kunt gebruiken om elke belofte af te wikkelen., Bijvoorbeeld voor het verwerken van netwerk-aanvragen, etc… De handtekening zal er als volgt uitzien:

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

De SpecFunction is net als de functie die u zou overgaan in de Promise constructor, met één uitzondering — het duurt een onCancel() handler:

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

Merk op dat dit voorbeeld is slechts een illustratie te geven van de kern van hoe het werkt. Er zijn een aantal andere edge gevallen die je nodig hebt om rekening te houden., Bijvoorbeeld, in deze versie zal handleCancel aangeroepen worden als je de belofte annuleert nadat deze al is afgewikkeld.

Ik heb een onderhouden productieversie hiervan geïmplementeerd met edge cases gedekt als de open source library, Speculation.

laten we de verbeterde bibliotheekabstractie gebruiken om het annulerbare wait() hulpprogramma van daarvoor te herschrijven., Installeer eerst speculatie:

npm install --save speculation

nu kunt u het importeren en gebruiken:

dit vereenvoudigt de zaken een beetje, omdat u zich geen zorgen hoeft te maken over denoop(), fouten opvangen in uwonCancel(), functie of andere randgevallen. Deze gegevens zijn weggeabstraheerd met speculation(). Check it out en voel je vrij om het te gebruiken in echte projecten.,

Extra ‘ s van de Native js Promise

het native Promise object heeft wat extra ‘ s waarin u wellicht geïnteresseerd bent:

  • Promise.reject() geeft een geweigerde belofte terug.
  • Promise.resolve() geeft een opgeloste belofte terug.
  • Promise.race() neemt een array (of een iterable) en geeft een belofte terug die oplost met de waarde van de eerste opgeloste belofte in de iterable, of afwijst met de reden van de eerste belofte die afwijst.,
  • Promise.all() neemt een array (of een iterable) en geeft een belofte terug die oplost wanneer alle beloften in het iterable argument zijn opgelost, of verwerpt met de reden van de eerst doorgegeven belofte die verwerpt.

conclusie

Beloften zijn een integraal onderdeel geworden van verschillende idiomen in JavaScript, waaronder de WHATWG Fetch-standaard die wordt gebruikt voor de meeste moderne Ajax-verzoeken, en de Async-Functiestandaard die wordt gebruikt om asynchrone code synchroon te laten lijken.,

Async functies zijn Fase 3 op het moment van dit schrijven, maar ik voorspel dat ze binnenkort een zeer populaire, veelgebruikte oplossing zullen worden voor asynchrone programmering in JavaScript — wat betekent dat het leren waarderen van Beloften in de nabije toekomst nog belangrijker zal zijn voor JavaScript-ontwikkelaars.

bijvoorbeeld, als je Redux gebruikt, stel ik voor dat je redux-saga bekijkt: een bibliotheek die gebruikt wordt om bijwerkingen in Redux te beheren die afhankelijk is van async functies in de hele documentatie.,

Ik hoop dat zelfs ervaren promise-gebruikers een beter begrip hebben van wat beloften zijn en hoe ze werken, en hoe ze beter te gebruiken na het lezen van dit.

bekijk de reeks

  • Wat is een afsluiting?
  • Wat is het verschil tussen klasse en Prototypale overerving?
  • Wat is een zuivere functie?
  • Wat is Functiesamenstelling?
  • Wat is functioneel programmeren?
  • Wat is een belofte?
  • Soft Skills

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *