Heim  >  Artikel  >  Web-Frontend  >  Ereignisse und Ereignisschleifen in NodeJS verstehen

Ereignisse und Ereignisschleifen in NodeJS verstehen

青灯夜游
青灯夜游nach vorne
2020-12-08 17:40:073189Durchsuche

Ereignisse und Ereignisschleifen in NodeJS verstehen

Verwandte Empfehlungen: „nodejs Tutorial

Freunde, die mit JavaScript vertraut sind, sollten Ereignisse wie Mausbewegungen, Mausklicks, Tastatureingaben usw. verwendet haben. Wir hören diese Ereignisse in Javascript ab, um die entsprechende Verarbeitung auszulösen.

Es gibt auch Ereignisse in NodeJS und es gibt auch ein spezielles Ereignismodul für die spezielle Verarbeitung.

Simultane Ereignisse und Ereignisschleifen sind ebenfalls sehr wichtige Konzepte für den Aufbau asynchroner E/A in NodeJS.

Heute erfahren wir mehr darüber.

Events

nodejs bietet ein spezielles Modul für Ereignisse: lib/events.js.

Erinnern Sie sich, als wir über die Verwendung von NodeJS zum Aufbau eines Webservers sprachen?

const server = http.createServer((req, res) => {
  res.statusCode = 200
  res.setHeader('Content-Type', 'text/plain')
  res.end('welcome to www.flydean.com\n')
})

Hier löst jede Anfrage das Anfrageereignis aus.

Die Kern-API von NodeJS basiert auf einer asynchronen ereignisgesteuerten Architektur, daher gibt es in NodeJS viele Ereignisse.

Zum Beispiel: net.Server löst jedes Mal ein Ereignis aus, wenn eine neue Verbindung besteht, fs.ReadStream löst ein Ereignis aus, wenn eine Datei geöffnet wird, und stream löst ein Ereignis aus, wenn die Daten lesbar sind.

Sehen wir uns an, wie man ein Nodejs-Ereignis erstellt:

const EventEmitter = require('events')
const eventEmitter = new EventEmitter()

Es gibt zwei häufig verwendete Methoden in Ereignissen, nämlich on und emit.

on wird verwendet, um auf Ereignisse zu warten, und emit wird verwendet, um Ereignisse auszulösen.

eventEmitter.on('fire', () => {
  console.log('开火')
})

eventEmitter.emit('fire')

emit kann auch Parameter annehmen:

eventEmitter.on('fire', who => {
  console.log(`开火 ${who}`)
})

eventEmitter.emit('fire', '美帝')

Schauen Sie sich noch einmal die beiden Parameter an:

eventEmitter.on('fire', (who, when) => {
  console.log(`开火 ${who} ${when}`)
})

eventEmitter.emit('fire', '川建国','now')

Standardmäßig ruft EventEmitter alle Listener synchron in der Reihenfolge der Registrierung auf. Dies stellt die korrekte Reihenfolge der Ereignisse sicher und hilft, Race Conditions und Logikfehler zu vermeiden.

Wenn eine asynchrone Ausführung erforderlich ist, können Sie setImmediate() oder process.nextTick() verwenden, um in den asynchronen Ausführungsmodus zu wechseln.

eventEmitter.on('fire', (who, when) => {
    setImmediate(() => {
      console.log(`开火 ${who} ${when}`);
  });
})

eventEmitter.emit('fire', '川建国','now')

Darüber hinaus unterstützen Ereignisse auch mehrere andere Methoden:

once(): Einen einzelnen Listener hinzufügen

removeListener() / off(): Ereignis-Listener aus Ereignissen entfernen

removeAllListeners(): Alle Ereignis-Listener entfernen

Ereignisschleife

Wir wissen, dass der NodeJS-Code in einer Single-Threaded-Umgebung ausgeführt wird und jeweils nur eine Sache verarbeitet.

Diese Verarbeitungsmethode vermeidet das Problem der Datensynchronisierung in Multithread-Umgebungen und verbessert die Verarbeitungseffizienz erheblich.

Die sogenannte Ereignisschleife bedeutet, dass der Prozessor in einem Programmzyklus, nachdem er die Ereignisse dieses Zyklus verarbeitet hat, in den nächsten Ereigniszyklus eintritt und die Ereignisse des nächsten Ereigniszyklus verarbeitet. Dies ist ein Zyklus nach dem anderen.

Blockieren der Ereignisschleife

Wenn die Verarbeitung eines Ereignisses während der Ereignisverarbeitung blockiert wird, wirkt sich dies auf die Ausführung anderer Ereignisse aus. Wir können also sehen, dass in JS fast alle E/A nicht blockierend sind. Dies ist auch der Grund, warum es in JavaScript so viele Rückrufe gibt. Beispiel für eine Ereignisschleife Die Aufrufsequenz wird ebenfalls über den Stack implementiert.

Aber nicht alle Methoden in der Funktion werden auf den Stapel verschoben, und einige Methoden werden in die Nachrichtenwarteschlange gestellt.

Lassen Sie uns ein weiteres Beispiel geben:

const action2 = () => console.log('action2')

const action3 = () => console.log('action3')

const action1 = () => {
    console.log('action1')
    action2()
    action3()
}

action1()

Das Ergebnis der Ausführung des obigen Codes:

action1
action2
action3

Das Ergebnis ist anders. Dies liegt daran, dass settimeout den Timer auslöst. Wenn der Timer abläuft, wird die Rückruffunktion zur Verarbeitung in die Nachrichtenwarteschlange gestellt, anstatt auf dem Stapel platziert zu werden.

Die Ereignisschleife priorisiert Ereignisse im Stapel. Erst wenn keine Daten im Stapel vorhanden sind, wechselt sie zu konsumierenden Ereignissen in der Nachrichtenwarteschlange.

Obwohl die Timeout-Zeit von setTimeout im obigen Beispiel 0 ist, muss noch gewartet werden, bis Aktion3 ausgeführt wird, bevor sie ausgeführt werden kann.

Beachten Sie, dass das Timeout in setTimeout nicht im aktuellen Thread wartet. Es wird vom Browser oder einer anderen JS-Ausführungsumgebung aufgerufen.

Jobwarteschlange und Versprechen

Versprechen in ES6 führt das Konzept der Jobwarteschlange ein, um das Ergebnis der asynchronen Funktion so schnell wie möglich auszuführen, anstatt es am Ende des Aufrufstapels zu platzieren.

Zum Beispiel:

const action2 = () => console.log('action2')

const action3 = () => console.log('action3')

const action1 = () => {
    console.log('action1')
    setTimeout(action2, 0)
    action3()
}

action1()

Ausgabeergebnis:

action1
action3
action2
Dies liegt daran, dass das Versprechen, das vor dem Ende der aktuellen Funktion aufgelöst wurde, unmittelbar nach der aktuellen Funktion ausgeführt wird.

Das heißt, zuerst wird der Stapel ausgeführt, dann wird die Jobwarteschlange ausgeführt und schließlich wird die Nachrichtenwarteschlange ausgeführt.

process.nextTick()

Lassen Sie mich zunächst eine Definition namens Tick geben. Ein Tick bezieht sich auf einen Ereigniszyklus. Process.nextTick() bezieht sich auf den Aufruf dieser Funktion, bevor der nächste Tick der Ereignisschleife beginnt:

const action2 = () => console.log('action2')

const action3 = () => console.log('action3')

const action1 = () => {
    console.log('action1')
    setTimeout(action2, 0)
    new Promise((resolve, reject) =>
        resolve('应该在action3之后、action2之前')
    ).then(resolve => console.log(resolve))
    action3()
}

action1()

NextTick muss also schneller sein als setTimeout der Nachrichtenwarteschlange.

setImmediate()

nodejs bietet eine setImmediate-Methode, um Code so schnell wie möglich auszuführen.

action1
action3
应该在action3之后、action2之前
action2

Die Funktion in setImmediate wird in der nächsten Iteration der Ereignisschleife ausgeführt. Die Funktionen von

setImmediate() und setTimeout(() => {}, 0) sind grundsätzlich ähnlich. Sie werden alle bei der nächsten Iteration der Ereignisschleife ausgeführt.

setInterval()

Wenn Sie bestimmte Rückruffunktionen regelmäßig ausführen möchten, müssen Sie setInterval verwenden.

setInterval(() => {
  console.log('每隔2秒执行一次');
}, 2000)

要清除上面的定时任务,可以使用clearInterval:

const id = setInterval(() => {
  console.log('每隔2秒执行一次');
}, 2000)

clearInterval(id)

注意,setInterval是每隔n毫秒启动一个函数,不管该函数是否执行完毕。

如果一个函数执行时间太长,就会导致下一个函数同时执行的情况,怎么解决这个问题呢?

我们可以考虑在回调函数内部再次调用setTimeout,这样形成递归的setTimeout调用:

const myFunction = () => {
  console.log('做完后,隔2s再次执行!');

  setTimeout(myFunction, 2000)
}

setTimeout(myFunction, 2000)

更多编程相关知识,请访问:编程视频!!

Das obige ist der detaillierte Inhalt vonEreignisse und Ereignisschleifen in NodeJS verstehen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:flydean. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen