Heim > Artikel > Web-Frontend > Detaillierte Erläuterung des Ereignisschleifenmechanismus in NodeJS
In diesem Artikel erfahren Sie mehr über den Ereignisschleifenmechanismus in node. Es hat einen gewissen Referenzwert. Freunde in Not können sich darauf beziehen. Ich hoffe, es wird für alle hilfreich sein.
Frontend-Entwicklung ist untrennbar mit JavaScript verbunden. JavaScript ist eine Web-Frontend-Sprache, die hauptsächlich in der Webentwicklung verwendet und vom Browser analysiert und ausgeführt wird. Die Rolle von js ist nicht nur auf die Front-End-Entwicklung beschränkt, sondern kann auch für die serverseitige Entwicklung verwendet werden – Nodejs. Wenn Sie als Front-End-Mensch mit Idealen und Ambitionen Ihren Horizont erweitern und eine serverseitige Entwicklungssprache beherrschen möchten, ist NodeJS eine sehr gute Wahl.
Verwandte Empfehlungen: „nodejs Tutorial“
Da Sie die js-Entwicklungsmethode beherrschen, ist der Einstieg in Node einfach, und das NPM-Paketverwaltungstool verbessert auch die Entwicklungserfahrung erheblich. Nodejs ist bekannt für seine asynchrone, nicht blockierende E/A-Arbeitsmethode und sein Verarbeitungsmechanismus wird als Ereignisschleife bezeichnet.
Wenn Sie den Knotenereignisschleifenmechanismus verstehen, können Sie die Ereignisverarbeitungsmethode des Knotens und den Ausführungszeitpunkt asynchroner Ereignisse besser verstehen. In diesem Artikel wird hauptsächlich der Ereignisschleifenmechanismus von NodeJS erläutert und die Grundlage für das anschließende Lernen des Knotens gelegt.
Wie bereits erwähnt, ist Javascript eine Web-Front-End-Sprache, die hauptsächlich in der Webentwicklung verwendet wird und vom Browser analysiert und ausgeführt wird, während node.js eine darauf basierende JavaScript-Laufumgebung ist Die Chrome V8-Engine ist also keine Sprache, keine Bibliothek, kein Framework, sondern eine JS-Laufzeitumgebung. Einfach ausgedrückt: Node kann JS-Code analysieren und ausführen. Früher konnten nur Browser JS analysieren und ausführen, aber jetzt kann Node dafür sorgen, dass JS vollständig ohne den Browser ausgeführt wird.
Es gibt viele Unterschiede zwischen node.js und Browser-js. Beispielsweise enthält js im Browser Ecmascript, BOM und DOM, aber js in nodejs verfügt nicht über BOM und DOM, sondern nur über emcscript. Und die JS-Ausführungsumgebung des Knotens bietet einige Betriebs-APIs auf Serverebene für JS, z. B. Lesen und Schreiben von Dateien, Aufbau von Netzwerkdiensten, Netzwerkkommunikation, http-Server usw. Die meisten dieser APIs sind in Kernmodule gepackt. Darüber hinaus unterscheidet sich der Ereignisschleifenmechanismus des Knotens vom Ereignisschleifenmechanismus des Browser-JS.
Jeder ist sich bereits über die js-Ereignisschleife im Browser im Klaren. Zum Vergleich werde ich sie hier kurz erwähnen.
Bei der Ausführung von js gelangen synchrone und asynchrone Aufgaben in unterschiedliche Ausführungsumgebungen. Synchrone Aufgaben gelangen in den Hauptthread, dh in den Hauptausführungsstapel, und asynchrone Aufgaben (Ajax-Anforderungen, Settimeout, Setinterval, Poromise.resolve () usw.) ) Geben Sie die Aufgabenwarteschlange ein. Verschiedene asynchrone Aufgaben werden in verschiedene Aufgabenwarteschlangen verschoben, z. B. Ajax-Anforderungen, Settimeout, Setinterval usw. Diese Aufgaben werden in die Makroaufgabenwarteschlange (Makroaufgabe) verschoben, während die Promise-Funktion in die Mikroaufgabenwarteschlange verschoben wird ( Mikroaufgabe). Der gesamte Ereignisschleifenprozess ist wie folgt:
Wenn der synchrone Code ausgeführt wird, wird der Hauptausführungsstapel leer und die Vorbereitungen für die Ausführung asynchroner Aufgaben beginnen.
Der Hauptthread prüft, ob die Mikrotask-Warteschlange leer ist. Wenn sie nicht leer ist, durchläuft er alle Mikrotasks in der Warteschlange, um sie auszuführen, löscht die Mikrotask-Warteschlange und überprüft dann die Makrotask-Warteschlange. Wenn die Mikrotask-Warteschlange leer ist, fahren Sie direkt mit dem nächsten Schritt fort.
Der Hauptthread durchläuft die Makroaufgabenwarteschlange und führt die erste Makroaufgabe in der Makroaufgabenwarteschlange aus. Wenn er während der Ausführung auf eine Makroaufgabe oder Mikroaufgabe stößt, wird er diese weiterhin in die entsprechende Aufgabenwarteschlange verschieben Sobald eine Makroaufgabe ausgeführt wird, muss die Mikrotask-Warteschlange durchlaufen und geleert werden.
Führen Sie den Rendervorgang durch und aktualisieren Sie die Ansicht. Starten Sie die nächste Ereignisschleife. Wiederholen Sie die obigen Schritte, bis die beiden Aufgabenwarteschlangen gelöscht sind
var le=Promise.resolve(2); console.log(le) console.log('3') Promise.resolve().then(()=>{ console.log('Promise1') setTimeout(()=>{ console.log('setTimeout2') },0) }) setTimeout(()=>{ console.log('setTimeout1') Promise.resolve().then(()=>{ console.log('Promise2') }) },0);
Verwenden Sie den obigen Ereignisschleifenprozess zur Analyse:
Die Ereignisschleife des Knotens besteht aus sechs Phasen. In einer Ereignisschleife werden diese sechs Phasen nacheinander ausgeführt Ereignisverarbeitung abgeschlossen. Das Ablaufdiagramm der sechs Stufen sieht wie folgt aus:
六个阶段分别是:
事件循环中,每当进入某一个阶段,都会从该阶段对应的回调队列中取出函数去执行。当队列为空或者执行的回调函数数量到达系统设定的阈值,该阶段就会终止,然后检查NextTick队列和微任务队列,将其清空,之后进入下一个阶段。
这里面比较关键的是poll阶段:
同样的举个大大的,看看以下代码会输出什么:
console.log('start') setTimeout(() => { console.log('timer1') Promise.resolve().then(function() { console.log('promise1') }) }, 0) setTimeout(() => { console.log('timer2') Promise.resolve().then(function() { console.log('promise2') }) }, 0) Promise.resolve().then(function() { console.log('promise3') }) console.log('end')
利用node事件循环分析呗:
因此输出顺序是:start,end,promise3,timer1,promise1,timer2,promise2,如果能正确回答出来说明对node的循环机制有了大体的了解,实际node输出结果确实是这样:
那如下代码会输出什么呢?
process.nextTick(function(){ console.log(7); }); new Promise(function(resolve){ console.log(3); resolve(); console.log(4); }).then(function(){ console.log(5); }); process.nextTick(function(){ console.log(8); });
继续分析:
因此最终输出是:3,4,7,8,5,需要记住,process.nextTick 永远大于 promise.then的优先级
还有一个大家很容易混淆的点就是setTimout和setImmediate的执行时机,根据上面描述的node事件循环机制,setImmediate()应该在check阶段执行 与 而setTimeout在timer阶段执行,理论上setTimout比setImmediate先执行,看下面的代码:
setTimeout(() => console.log(1),0); setImmediate(() => console.log(2));
执行结果是什么?1,2 还是 2,1,其实都有可能,看实际node运行的结果:
可以看到两次执行的结果不一样,为什么呢?原因在于即使setTimeout的第二个参数默认为0,但实际上,Node做不到0秒就执行其回调,最少也要4毫秒。那么进入事件循环后,如果没到4毫秒,那么timers阶段就会被跳过,从而进入check阶段执行setImmediate回调,此时输出结果是:2,1;
如果进入事件循环后,超过4毫秒(只是个大概,具体值并不确定),setTimeout的回调会出现在timer阶段的队列里,回调将被执行,之后再进入poll阶段和check阶段,此时输出结果是:1,2
那如果两者在I/O周期内调用,谁先执行呢?看一下代码:
const fs = require('fs') fs.readFile('./test.txt', 'utf8' , (err, data) => { if (err) { console.error(err) return } setTimeout(() => { console.log('timeout'); }, 0); setImmediate(() => { console.log('immediate'); }); })
实际上,node中输出的结果总是immediate先输出,timeout后输出。因为I/O回调是在poll阶段执行,当回调执行完毕之后队列为空,发现存在setImmediate的回调就会进入check阶段,执行完毕后,再进入timer阶段。
本文结合代码示例,对node的事件循环机制做了比较详细描述。通过这篇文章,应该可以了解浏览器的事件循环机制是怎样的,node的循环机制是怎样的,以及nextTick和micro队列的优先级,setTimout和setImmediate执行时机等一些容易混淆的知识点。文章中不足和不对之处,欢迎在评论区交流讨论,一起探索,谢谢。
更多编程相关知识,请访问:编程入门!!
Das obige ist der detaillierte Inhalt vonDetaillierte Erläuterung des Ereignisschleifenmechanismus in NodeJS. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!