Heim >Web-Frontend >js-Tutorial >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.
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
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.
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.
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
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.
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
setImmediate() und setTimeout(() => {}, 0) sind grundsätzlich ähnlich. Sie werden alle bei der nächsten Iteration der Ereignisschleife ausgeführt.
setInterval()
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!