Node.js Handbuch, Teil 7: Asynchrone Programmierung

In der Übersetzung des siebten Teils des Node.js-Handbuchs werden wir heute über asynchrone Programmierung sprechen, Probleme wie die Verwendung von Rückrufen, Versprechungen und das Konstrukt async / await berücksichtigen und die Arbeit mit Ereignissen diskutieren.




Asynchronität in Programmiersprachen


JavaScript selbst ist eine synchrone Single-Threaded-Programmiersprache. Dies bedeutet, dass Sie keine neuen Threads im Code erstellen können, die parallel ausgeführt werden. Computer sind jedoch von Natur aus asynchron. Das heißt, bestimmte Aktionen können unabhängig vom Ablauf der Hauptprogrammausführung ausgeführt werden. In modernen Computern wird jedem Programm eine bestimmte Prozessorzeit zugewiesen. Wenn diese Zeit abgelaufen ist, gibt das System auch für eine Weile Ressourcen an ein anderes Programm weiter. Solche Umschaltungen werden zyklisch durchgeführt, so schnell, dass eine Person es einfach nicht bemerken kann. Daher denken wir, dass unsere Computer viele Programme gleichzeitig ausführen. Dies ist jedoch eine Illusion (ganz zu schweigen von Multiprozessor-Maschinen).

Im Darm von Programmen werden Interrupts verwendet - Signale, die an den Prozessor übertragen werden und die Aufmerksamkeit des Systems auf sich ziehen. Wir werden nicht auf Details eingehen. Das Wichtigste ist, sich daran zu erinnern, dass asynchrones Verhalten, wenn ein Programm angehalten wird, bis es Prozessorressourcen benötigt, völlig normal ist. Zu einem Zeitpunkt, an dem das Programm das System nicht mit Arbeit lädt, kann der Computer andere Probleme lösen. Wenn ein Programm bei diesem Ansatz beispielsweise auf eine Antwort auf eine an ihn gerichtete Netzwerkanforderung wartet, blockiert es den Prozessor erst, wenn eine Antwort empfangen wird.

Programmiersprachen sind in der Regel asynchron. Einige von ihnen bieten dem Programmierer die Möglichkeit, asynchrone Mechanismen mithilfe der integrierten Sprachtools oder spezialisierter Bibliotheken zu steuern. Wir sprechen über Sprachen wie C, Java, C #, PHP, Go, Ruby, Swift, Python. Mit einigen von ihnen können Sie asynchron programmieren, Threads verwenden und neue Prozesse starten.

JavaScript-Asynchronität


Wie bereits erwähnt, ist JavaScript eine synchrone Sprache mit einem Thread. In JS geschriebene Codezeilen werden in der Reihenfolge ausgeführt, in der sie nacheinander im Text erscheinen. Hier ist beispielsweise ein ganz normales JS-Programm, das dieses Verhalten demonstriert:

const a = 1 const b = 2 const c = a * b console.log(c) doSomething() 

JavaScript wurde jedoch für die Verwendung in Browsern erstellt. Die Hauptaufgabe bestand zu Beginn darin, die Verarbeitung von Ereignissen im Zusammenhang mit Benutzeraktivitäten zu organisieren. Dies sind beispielsweise Ereignisse wie onClick , onMouseOver , onChange , onSubmit usw. Wie können solche Probleme im Rahmen eines synchronen Programmiermodells gelöst werden?

Die Antwort liegt in der Umgebung, in der JavaScript ausgeführt wird. Mit dem Browser können Sie nämlich solche Probleme effektiv lösen und dem Programmierer die entsprechenden APIs zur Verfügung stellen.

In der Umgebung von Node.js gibt es Tools zum Ausführen nicht blockierender E / A-Vorgänge, z. B. Arbeiten mit Dateien, Organisieren des Datenaustauschs über ein Netzwerk usw.

Rückrufe


Wenn wir über browserbasiertes JavaScript sprechen, kann festgestellt werden, dass es unmöglich ist, im Voraus zu wissen, wann der Benutzer auf eine Schaltfläche klickt. Um sicherzustellen, dass das System auf ein solches Ereignis reagiert, wird ein Handler dafür erstellt.

Der Ereignishandler akzeptiert eine Funktion, die beim Auftreten des Ereignisses aufgerufen wird. Es sieht so aus:

 document.getElementById('button').addEventListener('click', () => { //    }) 

Solche Funktionen werden auch Rückruffunktionen oder Rückrufe genannt.

Ein Rückruf ist eine reguläre Funktion, die als Wert an eine andere Funktion übergeben wird. Es wird nur aufgerufen, wenn ein bestimmtes Ereignis eintritt. JavaScript implementiert das Konzept erstklassiger Funktionen. Solche Funktionen können Variablen zugewiesen und an andere Funktionen übergeben werden (sogenannte Funktionen höherer Ordnung).

Ein gängiger Ansatz bei der clientseitigen JavaScript-Entwicklung besteht darin, dass der gesamte Clientcode in einen Listener des load eines window wird, der den Rückruf aufruft, der an ihn übergeben wird, nachdem die Seite betriebsbereit ist:

 window.addEventListener('load', () => { //  //     }) 

Rückrufe werden überall verwendet und nicht nur zur Behandlung von DOM-Ereignissen. Zum Beispiel haben wir uns bereits mit ihrer Verwendung in Timern getroffen:

 setTimeout(() => { //   2  }, 2000) 

XHR-Anforderungen verwenden auch Rückrufe. In diesem Fall sieht es so aus, als würde der entsprechenden Eigenschaft eine Funktion zugewiesen. Eine ähnliche Funktion wird aufgerufen, wenn ein bestimmtes Ereignis eintritt. Im folgenden Beispiel handelt es sich bei einem solchen Ereignis um eine Änderung des Anforderungsstatus:

 const xhr = new XMLHttpRequest() xhr.onreadystatechange = () => { if (xhr.readyState === 4) {   xhr.status === 200 ? console.log(xhr.responseText) : console.error('error') } } xhr.open('GET', 'https://yoursite.com') xhr.send() 

▍ Fehlerbehandlung bei Rückrufen


Lassen Sie uns darüber sprechen, wie Fehler in Rückrufen behandelt werden. Es gibt eine gemeinsame Strategie zur Behandlung solcher Fehler, die auch in Node.js verwendet wird. Es besteht darin, dass der erste Parameter einer Rückruffunktion ein Fehlerobjekt ist. Wenn keine Fehler null wird null in diesen Parameter geschrieben. Andernfalls wird ein Fehlerobjekt angezeigt, das seine Beschreibung und zusätzliche Informationen dazu enthält. So sieht es aus:

 fs.readFile('/file.json', (err, data) => { if (err !== null) {   //    console.log(err)   return } // ,   console.log(data) }) 

▍ Rückrufproblem


Rückrufe sind in einfachen Situationen bequem zu verwenden. Jeder Rückruf ist jedoch eine zusätzliche Ebene der Codeverschachtelung. Wenn mehrere verschachtelte Rückrufe verwendet werden, führt dies schnell zu einer erheblichen Komplikation der Codestruktur:

 window.addEventListener('load', () => { document.getElementById('button').addEventListener('click', () => {   setTimeout(() => {     items.forEach(item => {       //,  -      })   }, 2000) }) }) 

In diesem Beispiel werden nur 4 Codeebenen angezeigt. In der Praxis kann es jedoch zu einer großen Anzahl von Ebenen kommen, die normalerweise als "Rückrufhölle" bezeichnet werden. Sie können dieses Problem mit anderen Sprachkonstrukten lösen.

Versprechen und asynchron / warten


Beginnend mit dem ES6-Standard führt JavaScript neue Funktionen ein, die das Schreiben von asynchronem Code erleichtern und Rückrufe überflüssig machen. Wir sprechen über die Versprechen, die in ES6 erschienen sind, und das asynchrone / warten-Konstrukt, das in ES8 erschienen ist.

▍ Versprechen


Versprechen (Versprechenobjekte) sind eine der Möglichkeiten, mit asynchronen Softwarekonstrukten in JavaScript zu arbeiten, wodurch die Verwendung von Rückrufen im Allgemeinen reduziert wird.

Bekanntschaft mit Versprechen


Versprechen werden normalerweise als Proxy-Objekte für bestimmte Werte definiert, deren Erscheinungsbild in Zukunft erwartet wird. Versprechen werden auch "Versprechen" oder "versprochene Ergebnisse" genannt. Obwohl dieses Konzept seit vielen Jahren besteht, wurden Versprechen erst in ES2015 standardisiert und der Sprache hinzugefügt. In ES2017 ist das asynchrone / wartende Design erschienen, das auf Versprechungen basiert und als praktischer Ersatz angesehen werden kann. Selbst wenn Sie nicht vorhaben, regelmäßige Versprechen zu verwenden, ist daher ein Verständnis der Funktionsweise wichtig, um das asynchrone / warten-Konstrukt effektiv nutzen zu können.

Wie Versprechen funktionieren


Nachdem ein Versprechen aufgerufen wurde, geht es in einen ausstehenden Zustand über. Dies bedeutet, dass die Funktion, die das Versprechen verursacht hat, weiterhin ausgeführt wird, während einige Berechnungen im Versprechen ausgeführt werden, wonach das Versprechen darüber informiert. Wenn die vom Versprechen ausgeführte Operation erfolgreich abgeschlossen wurde, wird das Versprechen in den erfüllten Zustand versetzt. Ein solches Versprechen soll erfolgreich gelöst worden sein. Wenn der Vorgang mit einem Fehler abgeschlossen wird, wird das Versprechen in den abgelehnten Zustand versetzt.

Sprechen wir über die Arbeit mit Versprechungen.

Versprechen erstellen


Die API zum Arbeiten mit Versprechungen gibt uns den entsprechenden Konstruktor, der durch einen Befehl der Form new Promise() aufgerufen wird. So entstehen Versprechen:

 let done = true const isItDoneYet = new Promise( (resolve, reject) => {   if (done) {     const workDone = 'Here is the thing I built'     resolve(workDone)   } else {     const why = 'Still working on something else'     reject(why)   } } ) 

Promis überprüft die globale Konstante und wenn ihr Wert true , wird sie erfolgreich aufgelöst. Andernfalls wird das Versprechen abgelehnt. Mit den resolve und reject , die Funktionen sind, können wir Werte aus dem Versprechen zurückgeben. In diesem Fall geben wir eine Zeichenfolge zurück, aber hier kann ein Objekt verwendet werden.

Mit Versprechen arbeiten


Wir haben oben ein Versprechen erstellt und überlegen, jetzt damit zu arbeiten. Es sieht so aus:

 const isItDoneYet = new Promise( //... ) const checkIfItsDone = () => { isItDoneYet   .then((ok) => {     console.log(ok)   })   .catch((err) => {     console.error(err)   }) } checkIfItsDone() 

Das Aufrufen von checkIfItsDone() führt zur Ausführung des isItDoneYet isItDoneYet() -Versprechens und zur Organisation des Wartens auf dessen Lösung. Wenn das Versprechen erfolgreich aufgelöst wird, funktioniert der an die .then() -Methode übergebene Rückruf. Wenn ein Fehler auftritt, .catch() das Versprechen abgelehnt wird, kann es in der an die .catch() -Methode übergebenen Funktion verarbeitet werden.

Verkettungsversprechen


Versprechensmethoden geben Versprechungen zurück, sodass Sie sie zu Ketten kombinieren können. Ein gutes Beispiel für dieses Verhalten ist der browserbasierte API-Abruf , bei dem es sich um eine Abstraktionsschicht über XMLHttpRequest . Es gibt ein ziemlich beliebtes npm-Paket für Node.js, das die Fetch-API implementiert, auf die wir später noch eingehen werden. Diese API kann verwendet werden, um bestimmte Netzwerkressourcen zu laden und dank der Möglichkeit, Versprechen in Ketten zu kombinieren, die nachfolgende Verarbeitung heruntergeladener Daten zu organisieren. Wenn Sie die Fetch-API über einen Aufruf der Funktion fetch() aufrufen, wird ein Versprechen erstellt.

Betrachten Sie das folgende Beispiel für Verkettungsversprechen:

 const fetch = require('node-fetch') const status = (response) => { if (response.status >= 200 && response.status < 300) {   return Promise.resolve(response) } return Promise.reject(new Error(response.statusText)) } const json = (response) => response.json() fetch('https://jsonplaceholder.typicode.com/todos') .then(status) .then(json) .then((data) => { console.log('Request succeeded with JSON response', data) }) .catch((error) => { console.log('Request failed', error) }) 

Hier verwenden wir das npm-Paket node-fetch und die Ressource jsonplaceholder.typicode.com als Quelle für JSON-Daten.

In diesem Beispiel wird die Funktion fetch() verwendet, um ein TODO-Listenelement mithilfe einer Versprechungskette zu laden. Nach dem Ausführen von fetch() wird eine Antwort zurückgegeben, die viele Eigenschaften aufweist, von denen wir Folgendes interessieren:

  • status ist ein numerischer Wert, der den HTTP-Statuscode darstellt.
  • statusText - Eine statusText des HTTP-Statuscodes, die durch die Zeichenfolge OK wenn die Anforderung erfolgreich war.

Das response verfügt über eine json() -Methode, die ein Versprechen zurückgibt, bei dessen Auflösung der verarbeitete Inhalt des Anforderungshauptteils im JSON-Format dargestellt wird.

Vor diesem Hintergrund beschreiben wir, was in diesem Code geschieht. Das erste Versprechen in der Kette wird durch die von uns angekündigte Funktion status() , die den Status der Antwort überprüft. Wenn angezeigt wird, dass die Anforderung fehlgeschlagen ist (dh der HTTP-Statuscode liegt nicht im Bereich zwischen 200 und 299), wird das Versprechen abgelehnt. Diese Operation führt dazu, dass andere .then() in der Versprechenskette nicht ausgeführt werden und wir sofort zur .catch() -Methode gelangen, die zusammen mit der Fehlermeldung den Text Request failed an die Konsole ausgibt.

Wenn der HTTP-Statuscode zu uns passt, wird die von uns deklarierte Funktion json() aufgerufen. Da das vorherige Versprechen bei erfolgreicher Auflösung ein response zurückgibt, verwenden wir es als Eingabewert für das zweite Versprechen.

In diesem Fall geben wir die verarbeiteten JSON-Daten zurück, sodass das dritte Versprechen sie erhält. Anschließend wird in der Konsole eine Meldung angezeigt, dass aufgrund der Anforderung die erforderlichen Daten abgerufen werden konnten.

Fehlerbehandlung


Im vorherigen Beispiel hatten wir eine .catch() -Methode, die an eine Kette von Versprechungen angehängt war. Wenn etwas in der Kette der Versprechen schief geht und ein Fehler auftritt oder wenn sich herausstellt, dass eines der Versprechen abgelehnt wird, wird die Kontrolle auf den nächsten Ausdruck .catch() . Hier ist die Situation, in der ein Fehler in einem Versprechen auftritt:

 new Promise((resolve, reject) => { throw new Error('Error') }) .catch((err) => { console.error(err) }) 

Hier ist ein Beispiel für das Auslösen von .catch() nach dem Ablehnen eines Versprechens:

 new Promise((resolve, reject) => { reject('Error') }) .catch((err) => { console.error(err) }) 

Kaskadierende Fehlerbehandlung


Was .catch() wenn im Ausdruck .catch() ein Fehler auftritt? Um diesen Fehler zu behandeln, können Sie einen weiteren Ausdruck .catch() in die Kette der Versprechen aufnehmen (und dann der Kette so viele .catch() , wie erforderlich):

 new Promise((resolve, reject) => { throw new Error('Error') }) .catch((err) => { throw new Error('Error') }) .catch((err) => { console.error(err) }) 

Schauen wir uns nun einige nützliche Methoden an, mit denen Versprechen verwaltet werden.

Promise.all ()


Wenn Sie nach dem Auflösen mehrerer Versprechen eine Aktion ausführen müssen, können Sie dies mit dem Befehl Promise.all() tun. Betrachten Sie ein Beispiel:

 const f1 = fetch('https://jsonplaceholder.typicode.com/todos/1') const f2 = fetch('https://jsonplaceholder.typicode.com/todos/2') Promise.all([f1, f2]).then((res) => {   console.log('Array of results', res) }) .catch((err) => { console.error(err) }) 

In ES2015 wurde die Syntax der destruktiven Zuweisung angezeigt. Mit ihr können Sie Konstruktionen in der folgenden Form erstellen:

 Promise.all([f1, f2]).then(([res1, res2]) => {   console.log('Results', res1, res2) }) 

Hier haben wir als Beispiel den API-Abruf betrachtet, aber mit Promise.all() können Sie natürlich mit allen Versprechungen arbeiten.

Promise.race ()


Mit dem Befehl Promise.race() können Sie die angegebene Aktion ausführen, nachdem eines der an ihn übergebenen Versprechen aufgelöst wurde. Der entsprechende Rückruf mit den Ergebnissen dieses ersten Versprechens wird nur einmal aufgerufen. Betrachten Sie ein Beispiel:

 const first = new Promise((resolve, reject) => {   setTimeout(resolve, 500, 'first') }) const second = new Promise((resolve, reject) => {   setTimeout(resolve, 100, 'second') }) Promise.race([first, second]).then((result) => { console.log(result) // second }) 

Nicht erfasster TypeError-Fehler, der beim Arbeiten mit Versprechungen auftritt


Wenn Sie beim Arbeiten mit Versprechungen auf den nicht Uncaught TypeError: undefined is not a promise , stellen Sie sicher, dass beim Erstellen von Versprechungen das new Promise() Uncaught TypeError: undefined is not a promise anstelle von nur Promise() .

▍ asynchrones / wartendes Design


Das Async / Await-Konstrukt ist ein moderner Ansatz zur asynchronen Programmierung, der es vereinfacht. Asynchrone Funktionen können als eine Kombination von Versprechungen und Generatoren dargestellt werden, und im Allgemeinen ist diese Konstruktion eine Abstraktion über Versprechungen.

Das asynchrone / wartende Design reduziert die Menge an Boilerplate-Code, die Sie schreiben müssen, wenn Sie mit Versprechungen arbeiten. Als im ES2015-Standard Versprechungen auftauchten, zielten sie darauf ab, das Problem der Erstellung von asynchronem Code zu lösen. Sie haben diese Aufgabe bewältigt, aber in zwei Jahren, als sie die Ergebnisse der Standards ES2015 und ES2017 teilten, wurde klar, dass sie nicht als endgültige Lösung des Problems angesehen werden konnten.

Eines der Probleme, die Versprechen gelöst haben, war die berühmte „Hölle der Rückrufe“, aber sie haben bei der Lösung dieses Problems ihre eigenen Probleme ähnlicher Art geschaffen.

Versprechen waren einfache Konstrukte, um die man etwas mit einer einfacheren Syntax bauen konnte. Als die Zeit gekommen war, erschien das Konstrukt async / await. Durch seine Verwendung können Sie Code schreiben, der synchron aussieht, aber asynchron ist, insbesondere blockiert er den Hauptthread nicht.

Wie das Konstrukt async / await funktioniert


Eine asynchrone Funktion gibt ein Versprechen zurück, wie im folgenden Beispiel:

 const doSomethingAsync = () => {   return new Promise((resolve) => {       setTimeout(() => resolve('I did something'), 3000)   }) } 

Wenn Sie eine ähnliche Funktion aufrufen müssen, müssen Sie das Schlüsselwort await vor dem Befehl zum Aufrufen platzieren. Dies führt dazu, dass der aufrufende Code auf die Erlaubnis oder Ablehnung des entsprechenden Versprechens wartet. Es ist zu beachten, dass eine Funktion, die das Schlüsselwort await verwendet, mit dem async :

 const doSomething = async () => {   console.log(await doSomethingAsync()) } 

Kombinieren Sie die beiden obigen Codefragmente und untersuchen Sie ihr Verhalten:

 const doSomethingAsync = () => {   return new Promise((resolve) => {       setTimeout(() => resolve('I did something'), 3000)   }) } const doSomething = async () => {   console.log(await doSomethingAsync()) } console.log('Before') doSomething() console.log('After') 

Dieser Code gibt Folgendes aus:

 Before After I did something 

Der Text, den I did something wird mit einer Verzögerung von 3 Sekunden in die Konsole eingegeben.

Über Versprechen und asynchrone Funktionen


Wenn Sie eine bestimmte Funktion mit dem async , bedeutet dies, dass eine solche Funktion ein Versprechen async , auch wenn dies nicht explizit erfolgt. Aus diesem Grund ist das folgende Beispiel beispielsweise ein Arbeitscode:

 const aFunction = async () => { return 'test' } aFunction().then(console.log) //    'test' 

Dieser Entwurf ähnelt diesem:

 const aFunction = async () => { return Promise.resolve('test') } aFunction().then(console.log) //    'test' 

Stärken der Asynchronität / warten


Wenn Sie die obigen Beispiele analysieren, können Sie feststellen, dass der Code, der async / await verwendet, einfacher ist als der Code, der die Verkettung von Versprechungen verwendet, oder Code, der auf Rückruffunktionen basiert. Hier haben wir uns natürlich sehr einfache Beispiele angesehen. Sie können die oben genannten Vorteile voll ausschöpfen, indem Sie mit viel komplexerem Code arbeiten. Hier erfahren Sie beispielsweise, wie Sie JSON-Daten mithilfe von Versprechungen laden und analysieren:

 const getFirstUserData = () => { return fetch('/users.json') //      .then(response => response.json()) //  JSON   .then(users => users[0]) //      .then(user => fetch(`/users/${user.name}`)) //       .then(userResponse => userResponse.json()) //  JSON } getFirstUserData() 

So sieht die Lösung für dasselbe Problem mit async / await aus:

 const getFirstUserData = async () => { const response = await fetch('/users.json') //    const users = await response.json() //  JSON const user = users[0] //    const userResponse = await fetch(`/users/${user.name}`) //     const userData = await userResponse.json() //  JSON return userData } getFirstUserData() 

Verwenden von Sequenzen aus asynchronen Funktionen


Asynchrone Funktionen können leicht zu Designs kombiniert werden, die Promise-Ketten ähneln. Die Ergebnisse einer solchen Kombination sind jedoch viel besser lesbar:

 const promiseToDoSomething = () => {   return new Promise(resolve => {       setTimeout(() => resolve('I did something'), 10000)   }) } const watchOverSomeoneDoingSomething = async () => {   const something = await promiseToDoSomething()   return something + ' and I watched' } const watchOverSomeoneWatchingSomeoneDoingSomething = async () => {   const something = await watchOverSomeoneDoingSomething()   return something + ' and I watched as well' } watchOverSomeoneWatchingSomeoneDoingSomething().then((res) => {   console.log(res) }) 

Dieser Code gibt den folgenden Text aus:

 I did something and I watched and I watched as well 

Vereinfachtes Debugging


Versprechen sind schwer zu debuggen, da Sie mit ihnen die üblichen Tools des Debuggers (wie "Step Bypass", Step-Over) nicht effektiv verwenden können. Mit async / await geschriebener Code kann mit denselben Methoden wie normaler synchroner Code debuggt werden.

Ereignisgenerierung in Node.js.


Wenn Sie in einem Browser mit JavaScript gearbeitet haben, wissen Sie, dass Ereignisse eine große Rolle bei der Handhabung von Benutzerinteraktionen mit Seiten spielen. Es geht um die Behandlung von Ereignissen, die durch Klicks und Mausbewegungen, Tastenanschläge auf der Tastatur usw. verursacht werden. In Node.js können Sie mit Ereignissen arbeiten, die der Programmierer selbst erstellt. Hier können Sie mit dem Ereignismodul Ihr eigenes Ereignissystem erstellen. Dieses Modul bietet uns insbesondere die EventEmitter Klasse, mit deren Hilfe die Arbeit mit Ereignissen organisiert werden kann. Bevor Sie diesen Mechanismus verwenden können, müssen Sie ihn anschließen:

 const EventEmitter = require('events').EventEmitter 

Bei der Arbeit damit stehen uns unter anderem die Methoden on() und emit() zur Verfügung. Die emit Methode emit zum Aufrufen von Ereignissen verwendet. Die on Methode wird verwendet, um Rückrufe zu konfigurieren, Ereignishandler, die aufgerufen werden, wenn ein bestimmtes Ereignis aufgerufen wird.

Erstellen wir beispielsweise ein Startereignis. In diesem Fall geben wir etwas an die Konsole aus:

 eventEmitter = new EventEmitter(); eventEmitter.on('start', () => { console.log('started') }) 

Um dieses Ereignis auszulösen, wird die folgende Konstruktion verwendet:

 eventEmitter.emit('start') 

Als Ergebnis der Ausführung dieses Befehls wird der Ereignishandler aufgerufen und die started Zeichenfolge gelangt zur Konsole.

Sie können Argumente an den Ereignishandler übergeben und sie als zusätzliche Argumente für die emit() -Methode darstellen:

 eventEmitter.on('start', (number) => { console.log(`started ${number}`) }) eventEmitter.emit('start', 23) 

Dasselbe passiert in Fällen, in denen der Handler mehrere Argumente übergeben muss:

 eventEmitter.on('start', (start, end) => { console.log(`started from ${start} to ${end}`) }) eventEmitter.emit('start', 1, 100) 

EventEmitter Klassenobjekte verfügen über einige andere nützliche Methoden:

  • once() - Ermöglicht die Registrierung eines Ereignishandlers, der nur einmal aufgerufen werden kann.
  • removeListener() - Mit dieser removeListener() können Sie den an ihn übergebenen Handler aus dem Array der Handler des an ihn übergebenen Ereignisses entfernen.
  • removeAllListeners() - Ermöglicht das Entfernen aller Handler des an ihn übergebenen Ereignisses.

Zusammenfassung


Heute haben wir über asynchrone Programmierung in JavaScript gesprochen, insbesondere über Rückrufe, Versprechen und das Konstrukt async / await. Hier haben wir das Problem der Arbeit mit Ereignissen angesprochen, die vom Entwickler mithilfe des events . Unser nächstes Thema werden Netzwerkmechanismen der Node.js-Plattform sein.

Liebe Leser! Verwenden Sie beim Programmieren für Node.js das Konstrukt async / await?

Source: https://habr.com/ru/post/de424555/


All Articles