JavaScript: asynchrone programmeertechnieken. Terugbelfuncties

Om dit te schrijven stap voor stap instructies citeerde zoals altijd echte praktische problemen die verband hielden met validiteit programmacode plaats. Bij het corrigeren van de code in overeenstemming met de vereisten van het genoemde Doctype, bleek dat fouten direct optreden in de asynchrone secties van de Yandex.Metrica-teller. Dienovereenkomstig begon de zoektocht naar oplossingen voor dit probleem en werd het eindresultaat bereikt.

Het bleek dat validator.w3.org behoorlijk loyaal is aan de synchrone versie van de Yandex.Metrica-teller en informercode, maar gewoon verontwaardigd is als deze wordt vervangen door asynchrone secties. Het bleek ook dat Yandex.Metrica gebruikers (webmasters) de mogelijkheid biedt om synchroon of te kiezen asynchroon type teller naast andere aanvullende instellingen.

Daarom willen we onze lezer in deze korte stapsgewijze instructie vertellen hoe hij de synchrone Yandex.Metrica-code naar een asynchrone versie kan veranderen en omgekeerd. Aan al die lezers die weinig begrijpen waar dit allemaal over gaat we praten over, raden we aan om gewoon over te slaan deze instructies en ga verder met het lezen van belangrijkere en interessantere artikelen. En deze publicatie zal een zeer smalle en beperkte specificatie hebben.

ZEER BELANGRIJK: we zullen screenshots en gesproken tekst maken met behulp van de NIEUWE Metrica van Yandex. Dit zal correct zijn, sinds 22 juni 2015 deze versie zal de belangrijkste zijn, terwijl oud ontwerp Metrieken zullen geleidelijk tot het verleden behoren.

Synchrone en asynchrone Yandex.Metrica-tellercode: hoe te veranderen

Stap 1

Stap 2

We vinden in de lijst van onze sites de site waarvan de teller- of informantencode moet worden gewijzigd en starten de functie “Bewerken” (uitrusting met rechter zijde- V nieuwe versie Statistieken).

Stap 3

Bij de bewerkingsopties zijn we geïnteresseerd in het menu-item "Tellercode".

Stap 4

Hier zoeken we naar de “asynchrone” functie, al dan niet voorzien van een vinkje. Als er zo'n vinkje staat, zie je asynchrone code teller in na hieronder. Als u het selectievakje uitschakelt, wordt de Yandex.Metrica-tellercode standaard - synchroon.

Stap #5

Hier kunt u de aan- of afwezigheid van een INFORMER controleren en vaststellen. We hebben hier eerder over gesproken in een artikel op de site "". Deze instellingen zien er nu dus precies zo uit in de nieuwe versie van Metrica en worden hier gecorrigeerd.

Dat is eigenlijk alles. U kunt op elk moment:

— verander de asynchrone tellercode naar synchrone;
— installeer bijgewerkte en snelle asynchrone code;
- verwijder of voeg een Yandex.Metrica-tegeninformant toe.

De bijgewerkte tellercode moet in de website worden ingevoegd:

Tegenwoordig verschijnen er elke dag nieuwe programmeertalen - Go, Rust, CoffeeScript - wat dan ook. Ik besloot dat ik ook graag mijn eigen programmeertaal zou willen bedenken, dat de wereld een nieuwe taal miste...

Dames en heren, vandaag presenteer ik u Schlecht!Script - een gekke programmeertaal. We zouden het nu allemaal moeten gaan gebruiken. Het heeft alles wat we gewend zijn: het heeft Voorwaardelijke stellingen Er zijn cycli, er zijn functies en functies van hogere ordes. Over het algemeen heeft het alles wat een normale programmeertaal nodig heeft.

Wat er niet zo gebruikelijk aan is, wat op het eerste gezicht zelfs onaangenaam kan zijn, is dat in Schlecht!Script de functies kleuren hebben.


Dat wil zeggen dat wanneer u een functie declareert, wanneer u deze aanroept, u ​​expliciet de kleur ervan specificeert.

De functies zijn verkrijgbaar in rood en blauw - twee kleuren.

Belangrijk punt: Binnen blauwe functies kunt u alleen andere blauwe functies oproepen. Je kunt geen rode functies binnen blauwe functies oproepen.


Binnen rode functies kunt u zowel rode als blauwe functies oproepen.


Ik besloot dat het zo moest zijn. Zo zou het in elke taal moeten zijn.

Een subtiel punt: rode functies zijn pijnlijk om te schrijven en aan te roepen! Wat bedoel ik als ik 'pijn' zeg? Feit is dat ik nu Duits studeer, en ik heb besloten dat we allemaal alleen rode functies moeten noemen Duits, anders begrijpt de tolk eenvoudigweg niet wat u erin probeert te stoppen, en zal hij het eenvoudigweg niet doen.


Zo schrijf je functies in het Duits:


"!" vereist - we schrijven immers in het Duits.

Hoe schrijf je in zo'n taal? We hebben twee manieren. We kunnen alleen blauwe functies gebruiken, die niet pijnlijk zijn om te schrijven, maar intern kunnen we geen rode functies gebruiken. Deze aanpak zal niet werken omdat ik in een uitbarsting van inspiratie de helft heb geschreven standaard bibliotheek op rode functies, dus sorry...

Vraag aan u: zou u dergelijke taal gebruiken? Heb ik je Schlecht!Script verkocht?

Nou ja, je hebt eigenlijk geen keus. Sorry…

JavaScript is een geweldige taal, we zijn er allemaal dol op, we zijn hier allemaal omdat we van JavaScript houden. Maar het probleem is dat JavaScript enkele kenmerken van Schlecht!Script overneemt, en ik wil zeker niet opscheppen, maar ik denk dat ze een paar van mijn ideeën hebben gestolen.

Wat erven ze precies? JavaScript heeft rode en blauwe functies. Rode functies in JavaScript zijn asynchrone functies, blauwe functies zijn synchrone functies. En alles kan worden getraceerd, dezelfde keten... Rode functies zijn pijnlijk om aan te roepen in Schlecht!Script, en asynchrone functies zijn pijnlijk om aan te roepen in JavaScript.

En binnen blauwe functies kunnen we geen rode functies schrijven. Ik zal hier later meer over zeggen.


Waarom doet het pijn? Waar komt de pijn vandaan bij het aanroepen en schrijven van asynchrone functies?

We werken anders met voorwaardelijke instructies, lussen en return. Try/catch werkt niet voor ons, en asynchrone functies doorbreken de abstractie.

Over elk punt iets meer.


Dit is hoe synchrone code eruit ziet, waarbij ShouldProcess en Process synchrone functies zijn, en voorwaardelijke instructies werken, voor werken is over het algemeen alles in orde.

Hetzelfde, maar asynchroon, ziet er als volgt uit:

Daar verscheen recursie, we geven de staat door aan de parameters, aan de functie. Over het algemeen is het ronduit onaangenaam om naar te kijken. Try/catch werkt niet voor ons, en ik denk dat we allemaal weten dat als we een synchroon codeblok in try/catch verpakken, we de uitzondering niet zullen onderscheppen. We zullen een callback moeten doorgeven, de gebeurtenishandler opnieuw moeten koppelen, over het algemeen hebben we geen try/catch...

En asynchrone functies doorbreken de abstractie. Wat ik bedoel? Stel je voor dat je een cache hebt geschreven. U hebt een gebruikerscache in het geheugen gemaakt. En je hebt een functie die uit deze cache leest, die uiteraard synchroon is omdat alles in het geheugen staat. Morgen heb je duizenden, miljoenen, miljarden gebruikers, en je moet deze cache in Redis plaatsen. Je plaatst een cache in Redis, de functie wordt asynchroon, omdat we dankzij Redis alleen asynchroon kunnen lezen. En dienovereenkomstig zal de hele stapel die je synchrone functie heeft aangeroepen, moeten worden herschreven, omdat nu de hele stapel asynchroon wordt Deze functie was afhankelijk van de functie van het lezen uit de cache en zal nu ook asynchroon zijn.

Over het algemeen kunnen we, als we het hebben over asynchronie in JavaScript, zeggen dat alles daar triest is.

Maar wat hebben we allemaal te maken met asynchronie? Laten we het eindelijk even over mij hebben.


Ik kwam om jullie allemaal te redden. Nou, ik zal het proberen.

Mijn naam is Andrey, ik werk bij een startup genaamd Productive Mobile in Berlijn. Ik help met de organisatie van MoskouJS en ben co-host van RadioJS. Ik ben erg geïnteresseerd in het onderwerp asynchronie en niet alleen in JavaScript. Ik geloof dat dit in principe het beslissende moment van de taal is. De manier waarop een taal omgaat met asynchronie bepaalt het succes ervan en hoe plezierig en comfortabel mensen ermee werken.

Als we het specifiek hebben over asynchronie in JavaScript, denk ik dat we twee scripts hebben waarmee we voortdurend communiceren. Dit is de verwerking van meerdere gebeurtenissen en de verwerking van enkele asynchrone bewerkingen.

Een gebeurtenisset is zoiets als een DOM-gebeurtenis of een serververbinding - iets dat veel meerdere gebeurtenistypen uitzendt.

Een enkele handeling is bijvoorbeeld het lezen uit een database. Eén enkele asynchrone bewerking retourneert één resultaat of retourneert een fout. Er zijn geen opties meer.

En als we het over deze twee scenario’s hebben, is het interessant om te speculeren: asynchronie is slecht, over het algemeen is alles triest... Maar wat willen we echt? Hoe zou de ideale asynchrone code eruit zien?


En het lijkt mij dat we controlestroom van controle willen. We willen dat onze voorwaardelijke instructies en lussen in synchrone code op dezelfde manier werken als in asynchrone code.

Wij willen afhandeling van uitzonderingen. Waarom hebben we try/catch nodig als we het niet kunnen gebruiken in asynchrone bewerkingen? Het is gewoon raar.

En het is natuurlijk wenselijk om één enkele interface te hebben. Waarom zou een asynchrone functie anders geschreven en aangeroepen moeten worden dan een synchrone functie? Dit zou niet mogen gebeuren.

Dat is wat wij willen.

Wat hebben we vandaag de dag, en welke instrumenten zullen we in de toekomst hebben?


Als we het hebben over ECMAScript 6 (dit is in principe waar ik het vandaag over zal hebben), hebben we EventEmitter en Stream om met meerdere gebeurtenissen te werken, en Continuation Passing Style (ook wel callback genoemd) om met enkele asynchrone bewerkingen te werken. , Beloften en Coroutines.


In ECMAScript 7 zullen we Async Generators hebben voor het werken met meerdere gebeurtenissen en Async/Await voor het werken met enkele asynchrone bewerkingen.

Laten we hierover praten.

Laten we beginnen met wat we in ECMAScript 6 hebben om veel asynchrone gebeurtenissen af ​​te handelen. Ik wil u eraan herinneren dat dit bijvoorbeeld het verwerken van muisgebeurtenissen of toetsaanslagen betreft. We hebben een EventEmitter-patroon dat in de browser in Node.js is geïmplementeerd. Het is te vinden in vrijwel elke API waar we met veel evenementen werken. EventEmitter vertelt ons dat we een object kunnen maken dat gebeurtenissen uitzendt en handlers aan elk gebeurtenistype kunnen koppelen.


De interface is heel eenvoudig. We kunnen een EventListener toevoegen, een EventListener verwijderen met de naam van de gebeurtenis en daar een callback doorgeven.


Als ik in XMLHttpRequest bijvoorbeeld over meerdere gebeurtenissen praat, bedoel ik dat we meerdere voortgangsgebeurtenissen kunnen hebben. Die. Terwijl we sommige gegevens laden met behulp van een AJAX-verzoek, worden de voortgangsgebeurtenissen geactiveerd, en de gebeurtenissen laden, afbreken en fouten worden elk één keer geactiveerd:


Fout is een speciale gebeurtenis, een universele gebeurtenis in EventEmitter's en Stream's om de gebruiker op de hoogte te stellen van een fout.

Er zijn veel implementaties:


Er worden er hier slechts een paar vermeld, en aan het einde van het rapport vindt u een link waar al deze implementaties beschikbaar zijn.

Het is belangrijk om te zeggen dat EventEmitter standaard is ingebouwd in Node.js.

Dit is dus iets dat we bijna standaard hebben in de API en browsers in Node.js.

Wat hebben we nog meer voor het werken met meerdere evenementen? Stroom.

Stream is een gegevensstroom. Wat zijn gegevens? Dit kunnen binaire gegevens zijn, zoals bestandsgegevens, tekstgegevens of objecten of gebeurtenissen. De meest populaire voorbeelden:


Er zijn verschillende soorten stromen:


Hier kijken we naar een reeks conversies van Stylus-bestanden naar CSS-bestanden, waarbij we een autoprefixer toevoegen, omdat we allemaal dol zijn op Andrey Sitnik en zijn autoprefixer.

Je kunt zien dat we verschillende soorten streams hebben - de bronstream is gulp.src, die bestanden leest en bestandsobjecten uitzendt, die vervolgens streams gaan transformeren. De eerste conversiedraad is gemaakt van een stylus css-bestand, voegt de tweede transformatiethread voorvoegsels toe. En het laatste type thread is een consumententhread, die deze objecten ontvangt, ergens iets naar de schijf schrijft en niets uitzendt.


Die. we hebben 3 soorten stromen: gegevensbron, transformatie en consument. En deze patronen zijn overal te zien, niet alleen bij het slikken, maar ook bij het observeren van DOM-gebeurtenissen. We hebben threads die DOM-gebeurtenissen uitzenden, die ze transformeren, en iets dat deze DOM-gebeurtenissen verbruikt en een specifiek resultaat retourneert.

Dit is wat een transportband kan worden genoemd. Met behulp van stromen kunnen we dergelijke ketens bouwen wanneer een object ergens aan het begin van de lopende band wordt geplaatst, een keten van transformaties doorloopt en wanneer mensen het naderen, daar iets veranderen, toevoegen, verwijderen en uiteindelijk we eindigen met een auto.

Er zijn verschillende implementaties van streams, of ook Observables:


De ingebouwde streams in Node.js zijn Node Streams.

We hebben dus een EventEmitter en een Stream. EventEmitter is ook standaard aanwezig in alle API's. Stream is een add-on die we kunnen gebruiken om de interface voor het verwerken van meerdere gebeurtenissen te verenigen.


Als we het hebben over de criteria waarmee we asynchrone API's vergelijken, werken ze volgens ons niet over het algemeen, return-statements, looping-statements, try/catch werken uiteraard niet voor ons, en we zijn nog ver verwijderd van een uniforme interface met synchrone bewerkingen.

Over het algemeen is ECMAScript 6 niet erg goed voor het werken met meerdere evenementen.

Als we het hebben over afzonderlijke asynchrone bewerkingen, hebben we drie benaderingen in ECMAScript 6:


Continuation Passing Style, ook wel callback genoemd.


Ik denk dat jullie hier inmiddels allemaal aan gewend zijn. Dit is wanneer we dat doen asynchrone aanvraag, geven we daar een callback door, en de callback wordt aangeroepen met een fout of met een resultaat. Dit is een gebruikelijke aanpak en is ook beschikbaar in de browser in Node.


Ik denk dat jullie de problemen met deze aanpak ook allemaal begrijpen.


Dit is hoe we asynchroon een feed van gebruikerstweets zouden krijgen als alle functies synchroon zouden zijn.


Dezelfde code, maar synchroon, ziet er als volgt uit:


U kunt het lettertype vergroten, zodat het beter leesbaar is. En zoom nog een beetje verder in... En wij begrijpen heel goed dat dit Schlecht!Script is.


Ik zei dat ze mijn idee hadden gestolen.

Continuation Passing Style is een standaard in-browser API in Node.js, we werken er de hele tijd mee, maar het is lastig. Daarom hebben wij Beloften. Dit is een object dat een asynchrone bewerking vertegenwoordigt.


Een belofte is als een belofte om in de toekomst iets asynchroon te doen.


We kunnen een callback koppelen aan een asynchrone bewerking met behulp van de then-methode, en dit is in principe de hoofdmethode in de API. En we kunnen, heel belangrijk, Promises aan elkaar koppelen, we kunnen ze vervolgens opeenvolgend aanroepen, en elke functie die wordt doorgegeven aan, kan vervolgens ook Promises retourneren. Zo ziet het Twitter-feedverzoek van een gebruiker voor Promises eruit.

Als we deze aanpak vergelijken met de Continuation Passing Style, zijn beloften uiteraard handiger in het gebruik: ze geven ons de mogelijkheid om veel minder standaardteksten te schrijven.

Continuation Passing Style wordt nog steeds standaard in alle API's gebruikt, in Node.js, in io.js, en om verschillende redenen plannen ze niet eens overgangen naar Promises. In eerste instantie zeiden velen dat de redenen prestatie waren. En dit is waar, uit onderzoek uit 2013 blijkt dat Promises ver achterlopen op callbacks. Maar met de komst van bibliotheken als Bluebird kunnen we nu al vol vertrouwen zeggen dat dit niet het geval is, omdat Promises in Bluebird qua prestaties bijna callbacks benaderen. Een belangrijk punt: waarom worden Promises tot nu toe niet aanbevolen voor gebruik in API’s? Want als je Promises vanuit je API uitgeeft, dwing je de implementatie af.

Alle Promises van een bibliotheek moeten voldoen aan de standaard, maar met het uitbrengen van Promises geef je ook een implementatie uit, d.w.z. als je je code hebt geschreven met behulp van langzame Promises, en je geeft langzame Promises uit via de API, zal dat niet erg aardig zijn voor gebruikers. Daarom wordt het voor externe API's uiteraard nog steeds aanbevolen om callback te gebruiken".


Er zijn een heleboel implementaties van Promises, en als je nog niet je eigen implementatie hebt geschreven, ben je geen echte JavaScript-programmeur. Ik heb niet mijn eigen implementatie van Promises geschreven, dus moest ik mijn eigen taal bedenken.

Promises is dus over het geheel genomen iets minder dan een standaard, maar nog steeds niet zo goed.

Hoe zit het met Coroutines? Dit is waar dingen interessant beginnen te worden. Voorstellen…

Dit is interessant. We waren op JSConf in Boedapest, en er was een gek die een quadcopter en iets anders in JavaScript aan het programmeren was, en de helft van wat hij ons probeerde te laten zien, kon hij niet. Daarom zei hij voortdurend: "Oké, stel je nu eens voor... Deze quadcopter vertrok en alles kwam goed...".

Stel je voor dat we een functie op een bepaald punt tijdens de uitvoering ervan kunnen pauzeren.


Hier haalt de functie de naam van de gebruiker op, gaat naar de database, haalt het gebruikersobject op en retourneert zijn naam. Natuurlijk, "kom in de database" - de getUser-functie is asynchroon. Wat als we de getUserName-functie zouden kunnen pauzeren wanneer getUser wordt aangeroepen? Nu voeren we onze getUserName-functie uit, we moeten getUser en stopten. getUser ging naar de database, ontving een object, stuurde het terug naar de functie, we gaan door met de uitvoering. Hoe cool zou dat zijn?

Het punt is dat Coroutines ons deze kans geven. Coroutines zijn een functie die we op elk moment kunnen pauzeren en hervatten. Een belangrijk punt: we stoppen niet het hele programma.


Dit is een niet-blokkerende bewerking. Wij stoppen de uitvoering van een specifieke functie op een specifieke locatie.


Hoe ziet getUserName eruit met JavaScript-generatoren? We moeten "*" toevoegen aan de functiedeclaratie om aan te geven dat de functie een generator retourneert. We kunnen gebruiken trefwoord"yield" op de plaats waar we de functie willen pauzeren. En het is belangrijk om te onthouden dat getUser hier beloften retourneert.

Omdat Generatoren zijn oorspronkelijk uitgevonden om luie reeksen in JavaScript te maken; het gebruik ervan voor synchrone code is een hack. Daarom hebben we bibliotheken nodig die dit op de een of andere manier compenseren.


Hier gebruiken we "co" om de generator in te pakken en ons een asynchrone functie terug te geven.

Dus dit is wat we krijgen:


We hebben een functie waarin we if, for en andere operators kunnen gebruiken.

Om een ​​waarde terug te geven, schrijven we simpelweg return, net als bij een synchrone functie. We kunnen try/catch intern gebruiken en we zullen de uitzondering opvangen.


Als Promises with getUser een fout oplevert, wordt dit als een uitzondering gegenereerd.

De functie getUserName retourneert Promises, zodat we er op dezelfde manier mee kunnen werken als met alle Promises, we kunnen een callback toevoegen" en then, chain, enz. gebruiken.

Maar zoals ik al zei: het gebruik van generatoren voor asynchrone code is een hack. Daarom is het niet raadzaam om blootstelling als externe API te gebruiken. Maar het is prima om binnen een applicatie te gebruiken, dus gebruik het als je de mogelijkheid hebt om je code te transpileren.


Er zijn veel implementaties. Sommigen gebruiken generatoren, die al deel uitmaken van de standaard, er zijn Fibers, die werken in Node.js en die geen generator gebruiken, maar ze hebben hun eigen problemen.

Over het algemeen is dit de derde benadering voor het werken met afzonderlijke asynchrone bewerkingen, en dit is nog steeds een hack, maar we kunnen al code gebruiken die bijna synchroon is. We kunnen voorwaardelijke instructies, lussen en try/catch-blokken gebruiken.


Die. ECMAScript 6 voor het werken met enkele asynchrone bewerkingen lijkt ons iets dichter bij het gewenste resultaat te brengen, maar het probleem van een enkele interface is nog steeds niet opgelost, zelfs niet in Coroutines, omdat we een speciale “*” moeten schrijven en de “ rendement” key operator.


In ECMAScript 6 hebben we dus EventEmitter en Stream om met meerdere gebeurtenissen te werken, en om te werken met enkele asynchrone bewerkingen - CPS, Promises, Coroutines. En dit lijkt allemaal geweldig, maar er ontbreekt iets. Ik wil meer, iets moedigs, gedurfds, iets nieuws, ik wil een revolutie.

En de jongens die ES7 schrijven, besloten ons een revolutie te bezorgen en brachten Async/Await en Async Generators voor ons mee.


Async/Await is een standaard waarmee we met enkelvoudige asynchrone bewerkingen kunnen werken, zoals bijvoorbeeld databasequery's.

Dit is hoe we getUserName op generators schreven:


En zo ziet dezelfde code eruit met Async/Await:


Alles lijkt in grote lijnen erg op elkaar, dit is een stap verwijderd van een hack naar een standaard. Hier hebben we het trefwoord “async”, wat aangeeft dat de functie asynchroon is en een belofte zal retourneren. Binnen een asynchrone functie kunnen we het sleutelwoord "afwachten" gebruiken, waarbij we een belofte retourneren. En we kunnen wachten tot deze Belofte wordt vervuld, we kunnen de functie pauzeren en wachten tot deze Belofte wordt vervuld.


En dit is hoe voorwaardelijke operators, lussen en try/catch werken, dat wil zeggen dat asynchrone functies worden gelegaliseerd in ES7. Nu zeggen we expliciet dat als de functie asynchroon is, je het sleutelwoord "async" moet toevoegen. En dit is in principe niet zo erg, maar nogmaals, we hebben geen enkele interface.

Hoe zit het met meerdere evenementen? Hier hebben we een standaard genaamd Async Generators.

Wat is een setje precies? Hoe werken we met sets in JavaScript?


We werken met veelvouden met behulp van lussen, dus laten we met meerdere gebeurtenissen werken met behulp van lussen.


Binnen een asynchrone functie kunnen we de sleutelconstructie “for... on” gebruiken, waarmee we asynchrone verzamelingen kunnen herhalen. Alsof.

IN in dit voorbeeld observeren geeft ons iets terug dat we kunnen herhalen, d.w.z. Elke keer dat de gebruiker de muis beweegt, is er een “mousemove”-gebeurtenis. We bevinden ons in deze cyclus en verwerken deze gebeurtenis op de een of andere manier. IN in dit geval teken lijnen op het scherm.


Omdat De functie is asynchroon, het is belangrijk om te begrijpen dat deze een belofte retourneert. Maar wat als we veel waarden willen retourneren, als we bijvoorbeeld op een of andere manier berichten uit een websocket willen verwerken of filteren? Die. Er komt een menigte binnen en er komt een menigte naar buiten. Asynchrone generatoren helpen ons hierbij. We schrijven “asynchrone functie *” en zeggen dat de functie asynchroon is, en we retourneren een of andere set.


In dit geval kijken we naar de Message-gebeurtenis op de websocket en elke keer dat deze zich voordoet, voeren we een soort controle uit en als de controle slaagt, bevinden we ons in de geretourneerde collectie. Hoe zouden we dit bericht toevoegen?


Bovendien gebeurt dit allemaal asynchroon. Berichten worden niet verzameld, ze worden geretourneerd zodra ze binnenkomen. En al onze voorwaardelijke uitspraken, loops en try/catch werken hier ook.

Vraag: Wat retourneert filterWSMessages?


Dit is zeker geen belofte, want het is een soort verzameling, zoiets... Maar het is ook geen array.


Nog meer. Wat retourneren deze observaties die gebeurtenissen genereren?

En ze retourneren de zogenaamde Waarneembare objecten. Dit is een nieuw woord, maar over het algemeen zijn waarneembare stromen stromen, dit zijn stromen. Zo is de cirkel gesloten.

In totaal hebben we Async/Await voor het werken met asynchrone afzonderlijke bewerkingen, en Async Generators voor het werken met meerdere.

Laten we een wandeling maken en een kleine terugblik houden op waar we zijn gebleven en waar we naartoe zijn gekomen.

Om een ​​tweetfeed te krijgen, zouden we in CPS de volgende code schrijven:


Veel standaardwerk, foutafhandeling, praktisch handmatig en over het algemeen niet erg prettig.

Met Promise ziet de code er als volgt uit:


De standaard is kleiner, we kunnen uitzonderingen op één plek afhandelen, wat al goed is, maar toch zijn er deze dan..., noch try/catch noch voorwaardelijke operatoren werken.

Met Async/Await krijgen we de volgende constructie:


En Coroutines geven ons ongeveer hetzelfde.

Alles hier is geweldig, behalve dat we deze functie als “async” moeten declareren.

Als we het hebben over DOM-evenementen voor meerdere evenementen, dan is dit de manier waarop we muisbewegingen en tekenen over het scherm zouden afhandelen met behulp van de EventEmitter:


Dezelfde code, maar met behulp van Streams en de Kefir-bibliotheek, ziet er als volgt uit:


We creëren een stroom muisbewegingsgebeurtenissen in het venster, we filteren ze op de een of andere manier en voor elke waarde roepen we aan terugbelfunctie. En wanneer we deze stream beëindigen, zullen we ons automatisch afmelden voor evenementen in de DOM, wat belangrijk is

Asynchrone generatoren zien er als volgt uit:


Dit is slechts een lus, we doorlopen een verzameling asynchrone gebeurtenissen en voeren er enkele bewerkingen op uit.

Naar mijn mening is dit een enorme weg.

Tot slot zou ik graag een paar woorden willen zeggen over hoe je in feite kunt stoppen met het debuggen van asynchrone code en kunt gaan leven.

  • Definieer uw taak, d.w.z. als je met veel evenementen werkt, is het zinvol om naar Streams te kijken of misschien zelfs Async Generators als je een transpiler hebt.
  • Als u bijvoorbeeld met de database werkt en daar verzoeken verzendt of AJAX-verzoeken verzendt die mogelijk mislukken of worden voltooid, gebruikt u Promises.
  • Denk aan je beperkingen. Als je een transpiler kunt gebruiken, is het zinvol om naar Async/Await en Async Generators te kijken. Als u een API schrijft, is het misschien niet logisch om Promise als een externe API beschikbaar te stellen en alles via callbacks te doen.
  • Gebruik beste praktijken, onthoud foutgebeurtenissen op streams en op EventEmitter's.
  • Onthoud ongeveer speciale methoden zoals Promise.all, enz.

Ik weet dat jullie allemaal geïnteresseerd zijn in het lot van Schlecht!Script, wanneer het op GitHub zal worden geplaatst, enz., maar het feit is dat ze vanwege voortdurende kritiek, beschuldigingen van plagiaat zeggen dat zo'n taal al bestaat, niets nieuw niet uitgevonden, besloot ik het project te sluiten en mezelf misschien te wijden aan iets nuttigs, belangrijks, interessants, misschien schrijf ik zelfs mijn eigen Promises-bibliotheek.

Wij hebben vrijgelaten nieuw boek"Contentmarketing in in sociale netwerken: Hoe je in de hoofden van je abonnees kunt kruipen en ze verliefd kunt maken op je merk.”

Abonneren

Wat is asynchrone tellercode?

Asynchrone trackingcode (teller) is een scriptcode die in de hoofdtekst van de site wordt ingevoegd en is ontworpen om verkeersstatistieken bij te houden. Deze omvatten scripts Google Analytics en Yandex.Metrica.

Deze code wordt asynchroon genoemd omdat deze parallel met alle andere scripts wordt uitgevoerd. Wat betekent het?

Standaard wordt alle JavaScript opeenvolgend uitgevoerd, en als er een fout zit in de eerste code of een element dat het laden van andere scripts vertraagt, kan er een fout sluipen in het bijhouden van bezoekstatistieken.Asynchrone code wordt parallel met andere processen uitgevoerd en is de allereerste code wanneer de pagina wordt geladen. Dit garandeert een 100% respons en nauwkeurige gegevensverzameling.

De gegevens die door dit script worden verzonden, vormen statistische objecten. Deze omvatten:

  • paginaweergave;
  • externe transitie;
  • gebruiker.

Deze gegevens zijn nodig om een ​​algemeen beeld van de site te vormen: het aantal bezoekers, hun geslacht en leeftijd, geografie en tijd doorgebracht op de site, in- en uitstappagina's, enz.

Waar kan ik de Google Analytics- en Yandex.Metrica-code verkrijgen?

Om de code te krijgen Google Analytics wat je nodig hebt:

  1. Registreer of log in bij Google-services.
  2. Ga naar het tabblad “Administrators” en vul de velden “Accountnaam”, “Sitenaam”, “Site-URL” in. Het wordt aanbevolen om voor elke nieuwe site een nieuw account aan te maken.

3. Accepteer de gebruiksvoorwaarden.

  1. Hierna zijn de Google Analytics-ID's en trackingcode voor u beschikbaar.

Om asynchrone code in Yandex te ontvangen. Metriek:

  1. Registreer of log in op de dienst.
  2. Klik op de knop "Teller toevoegen".

  1. Er wordt een nieuw loketvenster geopend. Vul de velden in en vink het selectievakje 'Ik accepteer de voorwaarden' aan.

  1. Uw werfteller krijgt een nummer toegewezen. In het onderdeel “Tellercode” vindt u een code die u in de site kunt invoeren.

Waar moet ik de Google Analytics- en Yandex.Metrica-code plaatsen?

De nieuwe trackingcode wordt helemaal aan het begin van de pagina geplaatst, in een blok . In principe gebeurt dit via een editor of FTP.

Maar bent u bijvoorbeeld eigenaar van een website op WordPress, dan zijn er speciale plug-ins met de code “Google Analytics voor WordPress” of Google Analyticator voor u beschikbaar. U plakt eenvoudig uw tracking-ID in het veld Analytics-profiel en het systeem voert de autorisatie zelf uit.

Eigenaren van CMS OpenCart kunnen invoegen Google-code Analytics door de tabbladen Extensies -> Analytics te selecteren en de tellercode in het overeenkomstige Google Analytics-veld te plakken.

Ook kunnen eigenaren van dynamic.php-sites de code zelfstandig in het headerbestand invoegen. php, maar dit dreigt dat de code zal verdwijnen wanneer het systeem wordt bijgewerkt en opnieuw zal moeten worden gepost. Of maak een analyticstracking. php en voeg het toe aan alle sjablonen PHP-pagina's met een regel code onmiddellijk na de openingstag .

Kloon dus de repository en ga naar de Part_1 branch:

Git-kloon https://github.com/Peleke/promises/ git checkout Part_1-Basics

Je bent op het pad naar de waarheid. In onze route staan ​​de volgende vragen:

  • Probleem met terugbelfunctie
  • Beloften: definities en opmerkingen uit de specificatie
  • Beloften en niet-omkering van de controle
  • Flowcontrol met beloftes
  • Laten we de betekenis van dan begrijpen: afwijzen en oplossen

Asynchronie

Als je ooit met JavaScript hebt gewerkt, heb je al gehoord dat dit fundamenteel is niet-blokkerend of asynchroon. Maar wat betekent dit?

Synchrone en asynchrone code

Synchrone code wordt uitgevoerd vóór eventuele code die erop volgt. Je zult de term vaak tegenkomen blokkeren als synoniem voor synchroon omdat het de rest van het programma blokkeert totdat het is voltooid.

// readfile_sync.js "gebruik strikt"; // Dit voorbeeld komt van Node, dus voer het niet in een browser uit. const bestandsnaam = "tekst.txt", fs = require("fs"); console.log("Bestand lezen... "); // readFileSync BLOCKS totdat de waarde wordt geretourneerd. // Het programma wacht en doet niets // totdat deze bewerking is voltooid. const bestand = fs.readFileSync(`$(__mapnaam)/$(bestandsnaam)`); // Dit wordt ALTIJD uitgevoerd nadat readFileSync is voltooid. . . console.log("Klaar met lezen."); // . . . En hier wordt ALTIJD de inhoud van "bestand" weergegeven. console.log(`Inhoud: $(file.toString())`);

Asynchrone code Het tegenovergestelde is waar: het laat de rest van het programma draaien terwijl het bezig is met het verwerken van langlopende bewerkingen zoals I/O- of netwerkverzoeken. Het wordt ook wel genoemd niet-blokkerende code. Hier is de asynchrone analoog van het vorige fragment:

// readfile_async.js "gebruik strikt"; // Dit voorbeeld komt van Node, dus voer het niet in een browser uit. const bestandsnaam = "text.txt", fs = require("fs"), getContents = function printContent (bestand) ( try ( return file.toString(); ) catch (TypeError) ( return file; ) ) console.log( "Bestand lezen..."); console.log("=".herhaling(76)); // readFile wordt asynchroon uitgevoerd. // Het programma blijft doen wat er na LINE A komt // terwijl readFile zijn ding doet. We zullen binnenkort de callback-functies in detail bespreken, maar let voorlopig alleen op de volgorde van de logbestanden; fs.readFile(`$(__dirname)/$(filename)`, function (err, inhoud) ( file = inhoud; console.log(`Eh, eigenlijk ben ik nu klaar. De inhoud is: $( getContents(bestand ) )`); // LINE A // Dit wordt ALTIJD afgedrukt voordat het bestand is gelezen. // Deze logs zijn misleidend en nutteloos ))`); ;

Het belangrijkste voordeel van synchrone code is dat deze gemakkelijker te lezen en te begrijpen is: synchrone programma's worden van boven naar beneden uitgevoerd en regel n eindigt altijd vóór regel n+1.

Het grootste nadeel van synchrone code is de traagheid, die vaak pijnlijk is. Als u de browser elke keer dat de gebruiker een verzoek aan de server probeert te doen, twee seconden lang afremt, ontstaat er een extreem ongemak.

En dat is de reden waarom JavaScript in de kern non-blocking is gemaakt.

Asynchroon bellen

De overgang naar asynchronie geeft ons snelheid en neemt de lineariteit weg. Zelfs het eenvoudige script hierboven demonstreert dit. Herinneren:

  1. Er is geen manier om te weten wanneer een bestand beschikbaar zal zijn, behalve door de controle door te geven aan readFile , die ons zal vertellen wanneer het klaar is;
  2. Onze programma's worden niet langer in dezelfde volgorde uitgevoerd als waarin ze worden gelezen, waardoor ze moeilijker te begrijpen zijn.

Deze problemen zijn genoeg om ons tot het einde van het artikel bezig te houden.

Terugbelverzoeken en terugvalverzoeken

Laten we proberen ons readFile-voorbeeld een beetje te vereenvoudigen.

"gebruik strikt"; const bestandsnaam = "wegwerp.txt", fs = require("fs"); laat bestand, nutteloos; nutteloos = fs.readFile(`$(__dirname)/$(filename)`, function callback (fout, inhoud) ( file = inhoud; console.log(`Begrepen. De inhoud is: $(content)`); console. log(`. . . Maar nutteloos is nog steeds $(nutteloos).` )); // Met dank aan Rava voor het ontdekken van een fout in deze regel. console.log(`Bestand is $(nutteloos), maar dat zal snel veranderen.`);

Omdat readFile niet blokkeert, moet deze methode onmiddellijk terugkeren zodat het programma verder kan worden uitgevoerd. Omdat onmiddellijk dit is duidelijk niet genoeg om I/O-bewerkingen uit te voeren, de methode retourneert ongedefinieerd en we voeren het verdere programma zo vaak uit als we kunnen zonder readFile uit te voeren... Daarna lezen we het bestand.

De vraag is: hoe kunnen we weten dat de lezing voltooid is?

Helaas, op geen enkele manier. Maar readFile kan dat wel. In het bovenstaande codefragment hebben we readFile twee argumenten doorgegeven: de naam van het bestand en een functie genaamd terugbelfunctie, die we onmiddellijk willen uitvoeren nadat het bestand is gelezen.

Het werkt ongeveer als volgt: readFile kijkt naar wat zich in $(__dirname)/$(filename) bevindt en het programma gaat verder met zijn werk. Zodra readFile weet wat er staat, voert het een callback uit met de inhoud als argument, en als er een fout optreedt, retourneert het error .

Het is belangrijk om te begrijpen: we kunnen niet weten wanneer de inhoud van een bestand klaar zal zijn - alleen readFile kan dat. We geven er dus een callback-functie aan en vertrouwen erop dat deze deze correct gebruikt.

Dit is een gebruikelijk patroon voor het werken met asynchrone functies: roep ze aan met parameters en geef ze een callback-functie door om uit te voeren op het resulterende resultaat.

Terugbelfuncties zijn een werkbare oplossing, maar niet ideaal. Ze hebben er twee grote problemen:

  1. Omkering van controle
  2. Complexe foutafhandeling

Omkering van controle

Het eerste probleem is het vertrouwensprobleem.

Wanneer we readFile doorgeven aan onze callback-functie, vertrouwen we erop dat deze zal worden aangeroepen. En daar hebben we absoluut geen garanties voor. Net zoals er geen garantie is dat bij het oproepen de juiste parameters, in de juiste volgorde en het vereiste aantal keren worden doorgegeven.

In de praktijk is dit natuurlijk niet zo dodelijk: we schrijven al bijna 20 jaar callback-functies en hebben het internet nog steeds niet kapot gemaakt. En in dit geval weten we dat het veilig genoeg is om op Node te vertrouwen.

Maar het overdragen van de controle is van cruciaal belang belangrijke aspecten het delen van uw applicatie met een derde partij is riskant en is vaak de oorzaak van moeilijk te vinden Heisenbugs.

Impliciete foutafhandeling

In synchrone code kunt u try/catch/finally gebruiken om fouten af ​​te handelen.

"gebruik strikt"; // Dit voorbeeld komt van Node, dus voer het niet in een browser uit. const bestandsnaam = "tekst.txt", fs = require("fs"); console.log("Bestand lezen... "); laten bestand; poging ( // Verkeerde naam bestand. D"oh! file = fs.readFileSync(`$(__dirname)/$(filename + "a")`); console.log(`Begrepen. De inhoud is: "$(file)"`); ) catch ( err) ( console.log(`Er was een/n $(err): bestand is $(bestand)`); ) console.log("Fouten opvangen, zoals een bo$$.");

Asynchrone code probeert het natuurlijk, maar...

"gebruik strikt"; // Dit voorbeeld komt van Node, dus voer het niet in een browser uit. const bestandsnaam = "wegwerp.txt", fs = require("fs"); console.log("Bestand lezen... "); laten bestand; try ( // Onjuiste bestandsnaam. D"oh! fs.readFile(`$(__dirname)/$(bestandsnaam + "a")`, function (err, inhoud) ( file = inhoud; )); // Dit is zal niet worden uitgevoerd zolang het bestand ongedefinieerd is console.log(`Begrepen. De inhoud is: "$(file)"`); catch (err) ( // In dit geval zou catch moeten worden geactiveerd, maar dat gebeurt nooit. / / Dit komt omdat readFile fouten doorgeeft aan de callback // in plaats van deze terug te geven. console.log(`Er was een/n $(err): bestand is $(file)`);

Dit werkt niet zoals verwacht. Omdat het try-blok readFile omsluit, welke keert altijd succesvol terug ongedefinieerd. In een dergelijke situatie zal een poging altijd geen incident opleveren.

De enige manier De manier waarop readFile u over fouten kan vertellen, is door deze door te geven aan uw callback-functie, waar u ze zelf afhandelt.

"gebruik strikt"; // Dit voorbeeld komt van Node, dus voer het niet in een browser uit. const bestandsnaam = "wegwerp.txt", fs = require("fs"); console.log("Bestand lezen... "); fs.readFile(`$(__dirname)/$(bestandsnaam + "a")`, function (err, inhoud) ( if (err) ( // catch console.log(`Er was een/n $(err). `); ) else ( // probeer console.log(`Begrepen. De inhoud van het bestand is: "$(file)"`); ) ));

Dit voorbeeld is natuurlijk niet zo slecht, maar geef foutinformatie door aan grote programma's wordt snel onbeheersbaar.

Beloften lossen deze beide problemen en een aantal andere op zonder de controle om te keren en door onze asynchrone code te ‘synchroniseren’, zodat de vertrouwde foutafhandeling mogelijk is.

Beloften

Stel je voor dat je zojuist de volledige You Don't Know JS-catalogus bij O'Reilly hebt besteld. Voor je zuurverdiende geld hebben ze je een ontvangstbewijs gestuurd dat je aanstaande maandag een gloednieuwe stapel boeken ontvangt. Tot deze gelukkige maandag zul je geen boeken hebben, maar je gelooft dat ze zullen verschijnen, omdat ze beloofden je ze te sturen.

Deze belofte is voldoende zodat je, zelfs vóór de bevalling, tijd kunt inplannen voor dagelijks lezen, een paar boeken kunt uitkiezen om een ​​tijdje aan vrienden uit te lenen, en ook je baas kunt laten weten dat je het volgende week te druk zult hebben met lezen. naar het kantoor. Je hoeft geen boeken te hebben om zulke plannen te maken; je hoeft alleen maar te weten dat je ze krijgt.

Natuurlijk kan O’Reilly over een paar dagen melden dat maandag geen lot is en dat de boeken iets later zullen verschijnen, met andere woorden: de gewenste waarde zal in de toekomst liggen. Je beschouwt de belofte als een verwachte waarde en schrijft code alsof je deze al hebt.

Er is een kleine complicatie bij deze gebeurtenis: beloften behandelen de onderbreking van de volgorde van uitvoering van instructies intern en maken het gebruik van een speciaal catch-trefwoord mogelijk voor foutafhandeling. Dit wijkt enigszins af van de synchrone versie, maar is beter dan het coördineren van meerdere foutafhandelaars binnen ongecoördineerde callback-functies.

En zodra de belofte u een waarde oplevert, heeft u al besloten wat u ermee gaat doen. Dit lost het inversion-of-control-probleem op: u beheert uw applicatielogica rechtstreeks zonder de controle aan derden over te dragen.

The Promise Lifecycle: een kort overzicht van staten

Stel je voor dat je een belofte gebruikt om een ​​API aan te roepen.

Omdat de server niet onmiddellijk kan reageren, kan de belofte niet onmiddellijk de definitieve waarde of het foutenrapport bevatten. In deze staat worden beloften opgeroepen in behandeling. Dit is hetzelfde geval als het wachten op een stapel boeken in ons voorbeeld.

Zodra de server heeft gereageerd, hebben we twee mogelijke uitkomsten:

  1. De belofte krijgt de verwachte waarde, wat betekent dat het vervuld. Je boeken zijn gearriveerd.
  2. Ergens onderweg is er een fout opgetreden, een belofte afgewezen. Je hebt een melding ontvangen dat er geen boeken zullen zijn.

In totaal ontvangen wij drie mogelijke beloftestaten, terwijl de vooruitgangs- of afwijzingsstaten niet kunnen worden vervangen door een andere staat.

Nu we de basisconcepten hebben begrepen, gaan we kijken hoe we dit allemaal kunnen gebruiken.

Fundamentele beloftemethoden

Een belofte vertegenwoordigt het eindresultaat van een asynchrone operatie. De belangrijkste manier om met een belofte om te gaan, is door de toenmalige methode te gebruiken, die callback-functies registreert om het eindresultaat van de belofte te ontvangen of de reden te rapporteren waarom deze is mislukt.

In deze sectie gaan we er dieper op in basisgebruik beloften:

  1. Beloftes maken met een constructeur;
  2. Ga vastberaden om met een succesvol resultaat;
  3. Foutafhandeling bij afkeur;
  4. Flow control instellen met then en catch .

In ons voorbeeld zullen we beloftes gebruiken om de code van onze fs.readFile-functie op te schonen.

Beloftes creëren

De eenvoudigste manier is om rechtstreeks beloften te maken met behulp van de constructor.

"gebruik strikt"; const fs = vereisen("fs"); const tekst = new Promise(function (oplossen, afwijzen) ( // Doet niets ))

Merk op dat we een functie als argument doorgeven aan de belofteconstructor. Dit is waar we de belofte vertellen hoe de asynchrone bewerking moet worden uitgevoerd; wat we moeten doen als we krijgen wat we verwachten en wat we moeten doen als er een fout optreedt. In het bijzonder:

  1. Het oplossingsargument is een functie die samenvat wat we willen doen bij het ontvangen verwachte waarde. Wanneer we de verwachte waarde (val) ontvangen, geven we deze door als argument om op te lossen: solve(val) .
  2. Het afwijzingsargument is ook een functie die onze acties vertegenwoordigt in geval van een fout. Als we een fout (err) ontvangen, zullen we daarmee afkeuren: afwijzen(err) .
  3. Ten slotte verwerkt de functie die we aan de belofte-constructor hebben doorgegeven de asynchrone code zelf. Als het het verwachte resultaat oplevert, roepen we de oplossing aan met de resulterende waarde. Als er een fout optreedt, roepen we een afwijzing aan met die fout.

In ons voorbeeld zullen we fs.readFile in een belofte verpakken. Hoe moeten onze vastberadenheid en afwijzing eruit zien?

  1. Als dit lukt, willen we console.log aanroepen om de inhoud van het bestand uit te voeren.
  2. Als het niet lukt, doen we hetzelfde: we geven de fout weer in de console.

Zo krijgen we het volgende:

// constructor.js const solve = console.log, afwijzen = console.log;

Vervolgens moeten we een functie schrijven die we doorgeven aan de constructor. Vergeet niet dat we het volgende moeten doen:

  1. Bestand lezen;
  2. Indien succesvol, los het op met de inhoud ervan;
  3. Indien dit niet lukt, wijs dan af met de ontvangen foutmelding.

Dus:

// constructor.js const text = new Promise(function (oplossen, afwijzen) ( // Normale fs.readFile-oproep, maar binnen Promise-constructor . . fs.readFile("text.txt", function (err, text) ( / / . Roep 'reject' aan als er een fout is... if (err) 'reject(err);//' en bel 'resolve' anders. else // fs.readFile retourneert buffer, dus je moet de toString() gebruiken. .resolve(tekst.naarString());

Dus technisch gezien is alles klaar: deze code creëert een belofte die precies doet wat we nodig hebben. Maar als we deze code uitvoeren, zult u merken dat deze wordt uitgevoerd zonder enig resultaat of fout op te leveren.

Ze deed een belofte en toen...

Het probleem is dat we onze methoden voor vastberadenheid en afwijzing hebben geschreven, maar deze niet daadwerkelijk in de belofte hebben opgenomen. Om dit te kunnen doen, moeten we er nog één leren kennen basis functie om de stroom te controleren op basis van beloften: dan.

Elke belofte heeft een methode die twee functies als argumenten gebruikt: oplossen en afwijzen, in die volgorde. Door vervolgens een belofte aan te roepen en deze twee functies eraan door te geven, worden ze beschikbaar voor de belofteconstructeur.

// constructor.js const tekst = new Promise(function (oplossen, afwijzen) ( fs.readFile("text.txt", function (err, tekst) ( if (err) verwerp(err); else solve(text.toString) ()); )) )).dan(oplossen, afwijzen);

Dus de belofte zal het bestand lezen en de oplossingsmethode aanroepen die we hebben geschreven als dit lukt.

Het is dan belangrijk om dat te onthouden retourneert altijd een belofteobject. Dit betekent dat u meerdere oproepen kunt koppelen om een ​​complexe en synchroon ogende stroom over asynchrone bewerkingen te creëren. In het volgende artikel zullen we dit in meer detail bespreken, en we zullen begrijpen hoe het eruit ziet door het vangstvoorbeeld te analyseren.

Syntactische suiker voor foutafhandeling

We hebben toen twee functies doorgegeven: besluiten om te worden gebeld in geval van succes en afwijzen in geval van een fout.

Beloften hebben ook een toenmalige functie genaamd catch. Het neemt de afwijzingshandler als enige argument.

Omdat dan altijd een belofte wordt geretourneerd, kunnen we in ons voorbeeld alleen de oplossingshandler aan toen doorgeven en deze vervolgens met de afwijzingshandler verbinden met de catch-keten.

Const tekst = new Promise(functie (oplossen, afwijzen) ( fs.readFile("tex.txt", functie (err, tekst) ( if (err) afwijzen(err); else solve(text.toString()); ) ) )).dan(oplossen) .catch(afwijzen);

Ten slotte is het de moeite waard om te vermelden dat catch(reject) slechts syntactische suiker is voor then(undefinieerd, afwijzen) . Dat wil zeggen, we kunnen ook schrijven:

Const tekst = new Promise(functie (oplossen, afwijzen) ( fs.readFile("tex.txt", functie (err, tekst) ( if (err) afwijzen(err); else solve(text.toString()); ) ) )).dan(oplossen) .dan(ongedefinieerd, afwijzen);

Maar dergelijke code zal minder leesbaar zijn.

Conclusie

Beloften zijn dat onmisbaar hulpmiddel voor asynchrone programmering. In het begin kunnen ze intimiderend zijn, maar alleen totdat je ermee vertrouwd bent: gebruik ze een paar keer en ze zullen net zo natuurlijk voor je worden alsof / anders.

In het volgende artikel gaan we aan de slag met het converteren van op callback gebaseerde code naar code die beloften gebruikt en bekijken we , een populaire beloftebibliotheek.

Als aanvullende literatuur Bekijk Domenic Denicola's artikel States and Fates om inzicht te krijgen in de terminologie en het hoofdstuk van Kyle Simpson over beloften uit de stapel boeken waarin we vroeger naar beloften keken.

We raden vooral aan om asynchrone laadcode te gebruiken als uw sites erop zijn gebouwd AJAX-technologieën. Op deze manier kunt u inhoudsupdates instellen reclame blok wanneer de pagina-inhoud verandert of een andere gebeurtenis die u opgeeft.

"contentType":text/html"),"proposedBody":("source":

We raden vooral aan om asynchrone laadcode te gebruiken als uw sites zijn gebouwd op AJAX-technologie. Op deze manier kunt u configureren dat de inhoud van het advertentieblok wordt bijgewerkt wanneer de pagina-inhoud verandert of een andere gebeurtenis die u opgeeft.

We raden vooral aan om asynchrone laadcode te gebruiken als uw sites zijn gebouwd op AJAX-technologie. Op deze manier kunt u configureren dat de inhoud van het advertentieblok wordt bijgewerkt wanneer de pagina-inhoud verandert of een andere gebeurtenis die u opgeeft.

"contentType":text/html"),"authorId":119287251","slug":457"canEdit":false,"canComment":false,"isBanned":false,"canPublish" :false,"viewType "old" "isDraft":false,"isOnModeration":false,"isSubscriber":false,"commentsCount":21,"modificationDate": do 1 januari 1970 03:00:00 GMT +0000 (UTC)","showPreview":true,"approvedPreview":("source":"

We raden vooral aan om asynchrone laadcode te gebruiken als uw sites zijn gebouwd op AJAX-technologie. Op deze manier kunt u configureren dat de inhoud van het advertentieblok wordt bijgewerkt wanneer de pagina-inhoud verandert of een andere gebeurtenis die u opgeeft.

","html: "YAN-partners kunnen het laden van advertentieblokken op hun sites versnellen met behulp van nieuwe asynchrone code."contentType":text/html"),"proposedPreview":("source":

We raden vooral aan om asynchrone laadcode te gebruiken als uw sites zijn gebouwd op AJAX-technologie. Op deze manier kunt u configureren dat de inhoud van het advertentieblok wordt bijgewerkt wanneer de pagina-inhoud verandert of een andere gebeurtenis die u opgeeft.

","html: "YAN-partners kunnen het laden van advertentieblokken op hun sites versnellen met behulp van nieuwe asynchrone code."contentType":text/html"),"titleImage":null,"tags":[( "displayName "asynchrone code", "slug":asinkhronnyy-kod","categoryId"47982168", "url":/blog/partner??tag=asinkhronnyy-kod"),("displayName" :" partner interface", "slug":partnerskiy-interfeys","categoryId":25247736", "url":/blog/partner??tag=partnerskiy-interfeys"),("displayName":nieuws ", "slug":novost","categoryId":25247737";url":/blog/partner??tag=novost"),("displayName": advertentieblokken", "slug": reklamnye-bloki","categoryId":24650991","url":/blog/partner??tag=reklamnye-bloki")],"isModerator":false,"commentsEnabled":true,"url" /blog /partner/457", "urlTemplate":/blog/partner/%slug%", fullBlogUrl":https://yandex.ru/blog/partner", "addCommentUrl"/blog/createComment /partner /457", "updateCommentUrl"/blog/updateComment/partner/457", "addCommentWithCaptcha":/blog/createWithCaptcha/partner/457", "changeCaptchaUrl"/blog/api/captcha/new" ," putImageUrl":/blog/image/put", "urlBlog":/blog/partner", urlEditPost":/blog/56a93a7dd97351872e7341e0/edit", "urlSlug":/blog/post/generateSlug" ," urlPublishPostphoria:/blog/56a93a7dd97351872e7341e0/publish","urlUnpublishPostphoria:/blog/56a93a7dd97351872e7341e0/unpublish","urlRemovePost"/blog/56a93a7dd97351872e7341e 0/removePost","urlDraft" /blog/partner /457/ draft","urlDraftTemplate":/blog/partner/%slug%/draft","urlRemoveDraft"/blog/56a93a7dd97351872e7341e0/removeDraft","urlTagSuggest"/blog/api/suggest/partner" , "urlAfterDelete "/blog/partner", "isAuthor":false,"subscribeUrl":/blog/api/subscribe/56a93a7dd97351872e7341e0", "unsubscribeUrl":/blog/api/unsubscribe/56a93a7dd97351872e7341e0", "urlEditPostPage static: /blog/partner/56a93a7dd97351872e7341e0/edit","urlForTranslate":/blog/post/translate", "urlRelateIssue"/blog/post/updateIssue", "urlUpdateTranslate":/blog/post/updateTranslate "," urlLoadTranslatedice:/blog/post/loadTranslate","urlTranslationStatus":/blog/partner/457/translationInfo", "urlRelated Articles":/blog/api/related Articles/partner/457", "auteur" :(" id":false,"uid":("value":("value":false,"hosted":false),"aliases":(),"login"i. alex.under ","display_name":("name"i.alex.under",avatar":("default":("default":20706/119287251-18411626",leeg":false)),,"address static:i .alex..mds.yandex.net/get-yapic/20706/119287251-18411626/islands-middle","isYandexStaff":false),"originalModificationDate":1970-01-01T00:00:00.000 Z"," socialImage":("orig":("fullPath":http://avatars.yandex.net/get-yablog/4611686018427441880/normal"))))">