Heim >Web-Frontend >js-Tutorial >Ähnlichkeiten, Unterschiede und Teilmechanismen von EventLoop zwischen Browsern und NodeJS

Ähnlichkeiten, Unterschiede und Teilmechanismen von EventLoop zwischen Browsern und NodeJS

不言
不言Original
2018-07-07 17:23:572069Durchsuche

Dieser Artikel stellt hauptsächlich die Ähnlichkeiten, Unterschiede und einige Mechanismen von EventLoop zwischen Browsern und NodeJS vor. Jetzt kann ich ihn mit Ihnen teilen

Browser-Ähnlichkeiten und Unterschiede mit EventLoop von NodeJS und einige Mechanismen

Javascript ist eine Single-Thread-Skriptsprache, verfügt jedoch über viele asynchrone APIs, die Entwicklern bei der Lösung von Thread-Blockierungsproblemen helfen. Zum Beispiel: bei onClick registrierte Rückruffunktion, wesentliches Ajax usw. Aber wie erreicht die JavaScript-Ausführungsumgebung Single-Threading, ohne den Thread ständig zu blockieren und auf den Abschluss verschiedener asynchroner Vorgänge zu warten, bevor sie mit der Ausführung des Vorgangs fortfährt?
Die Antwort lautet: Ereignisschleife

1.event loop 的规范是在HTML5中规定的。
2.event loop 是 javascript 运行环境(手动加粗) 的机制。
3.浏览器实现的event loop 与 NodeJS 实现的event loop 是有异同的。
Link zur Ereignisschleifenspezifikation, definiert in HTML5 https://www.w3.org/TR/html5/w...


Ereignisschleife eines Browsers

1. Verstehen Sie kurz die

Ereignisschleife, die Ereignisschleife . Wie ist die Struktur? Der Blog von Lehrer Ruan Yifeng ist zwar sehr einfach und klar, es fehlen jedoch einige Dinge und er kann den gesamten Zirkulationsmechanismus der Ereignisschleife nicht vollständig demonstrieren. Schauen wir uns zuerst die Bilder an:
Ähnlichkeiten, Unterschiede und Teilmechanismen von EventLoop zwischen Browsern und NodeJS

Die Bilder sind nicht original vom Autor und stammen aus Ruan Yifengs Blog. Bitte beachten Sie, dass sie verletzt wurden gelöscht.

Die Informationen, die wir aus dem Bild erhalten können, sind:

1. Die Javascript-Engine führt Javascript in einem einzigen Thread aus, da es nur einen Stapel gibt, in dem es vorhanden ist verschiedene ausführende und wartende Prozesse. Ausgeführtes Ereignis.
2. Einige WebAPIs stellen den bei der Ausführung generierten Rückruf in eine Warteschlange, d. h. die „Ereigniswarteschlange“.
3. In der Ereignisschleife werden Ereignisse, die in der „Ereigniswarteschlange“ auf ihre Ausführung warten, kontinuierlich in den Javascript-Ausführungsstapel verschoben.

Dies ist der Mechanismus der Vereinfachung von Ereignisschleifen. Warum heißt er vereinfacht? Weil es viele Operationen und Regeln gibt, die in der Schleife nicht erwähnt werden.

Ich werde keine Kastanien nennen, aber ich werde eine Analogie geben.

Ähnlichkeiten, Unterschiede und Teilmechanismen von EventLoop zwischen Browsern und NodeJS

Ähnlichkeiten, Unterschiede und Teilmechanismen von EventLoop zwischen Browsern und NodeJS

Lassen Sie uns über eine häufig gestellte Frage sprechen (es ist umständlich, den Artikel zu bearbeiten, daher besteht er nur aus einer Zeile. Wenn Sie ein Zeilenwechsler sind, sind Sie herzlich willkommen. Schlagen Sie mich! Verzögerungen aufgrund von Blockierungen zur Verhinderung von Leverage), aber unabhängig davon: Wer auch immer die beiden Codezeilen nach oben oder unten geht, die Ausgabe ist

2 1

. Denn hierbei geht es um die Ausführungsreihenfolge und Regeln von Makroaufgabe und Mikroaufgabe in der Ereignisschleife.


2. Gesamtprozess

Um auf das Problem zurückzukommen, dass das gerade erwähnte Flussdiagramm nicht perfekt genug ist, finden Sie hier ein vollständiges und umfassendes Flussdiagramm für die Ereignisschleife.

Ähnlichkeiten, Unterschiede und Teilmechanismen von EventLoop zwischen Browsern und NodeJS

Das Bild ist kein Original des Autors und stammt von Secrets of Javascript Ninja. Bitte beachten Sie, dass es verletzt und gelöscht wird. Dies ist ein vollständiges Flussdiagramm einer Ereignisschleife. Auf dem Bild können wir viele Substantive sehen, die gerade nicht erwähnt wurden nach unten):

1. Lesen Sie die Aufgaben in der Makrotask-Warteschlange. Es gibt zwei Situationen:

    Die Aufgabenwarteschlange ist leer und die nach unten ausgeführte
  • Aufgabenwarteschlange ist nicht leer und die erste eingegebene
  • eins

    (manuell + fett im Artikel) Die Aufgabe wird in den Javascript-Ausführungsstapel verschoben und nach unten ausgeführt

  • 2. Lesen Sie die Aufgaben in der Microtask-Warteschlange. Es gibt zwei Situationen:
    Die Aufgabenwarteschlange ist leer, nach unten ausführen
  • Die Aufgabenwarteschlange ist nicht leer, die erste eingegebene Aufgabe jedoch in den Javascript-Ausführungsstapel geschoben und
  • diesen Vorgang noch einmal wiederholen

    (Handbuch + Artikel fett gedruckt), bis die Microtask-Warteschlange leer ist. Um es ganz klar auszudrücken: Schieben Sie alle Aufgaben aus dieser Aufgabenwarteschlange der Reihe nach in den Javascript-Ausführungsstapel und führen Sie sie nach unten aus

  • Dieses Mal gemäß
Zykluszeit
(manuell + fett im Artikel) Bestimmen Sie, ob benötigt und ob die Benutzeroberfläche aktualisieren kann [Ich werde dieses Problem mit der Zykluszeit später erwähnen]
    Keine Notwendigkeit, wiederholen Sie den ersten Schritt
  • Notwendig, fahren Sie mit dem nächsten Schritt fort
  • 4 Rendering und blockiert gleichzeitig die Ausführung von Javascript. Und wiederholen Sie weiterhin Schritt eins.
Das Obige ist ein vollständiger Ereignisschleifenprozess. Aus dem Prozess können wir ersehen, dass es zwei „Aufgabenwarteschlangen“ gibt. Die API zum Instanziieren dieser beiden Warteschlangen in Javascript lautet
setTimeout(e=>{ console.log(1) },0);

new Promise((res,rej)=>{ res() }).then(e=>{ console.log(2) });

An diesem Punkt ist ein vollständiger Ereignisschleifenprozess vollständig abgeschlossen.

3.实例解析
什么鬼?这么复杂? 弄懂?不存在的
Ähnlichkeiten, Unterschiede und Teilmechanismen von EventLoop zwischen Browsern und NodeJS

现在回到刚才提到的 “老生常谈的问题” 从实例的角度来说明一下问题。我们假设这个 javascript 文件叫做 "main.js"
"main.js"中的代码(+ 为自定义标记)

+1 console.log(1);

+2 setTimeout(e=>{ console.log(2); },0)

+3 setTimeout(e=>{ console.log(3); },0)

+4 new Promise((resolve,reject)=>{ console.log(4); resolve();})
.then(e=>{ console.log(5); })

+5 setTimeout(e=>{ console.log(6);

  +6 new Promise((resolve,reject)=>{ console.log(7); resolve(); })
     .then(e=>{ console.log(8);})
})

那么这个执行顺序是怎样呢?从头带尾梳理一遍(词穷,全文只要是流程统一是“从头到尾梳理一遍”)

macrotask: javascript 代码,所有同步代码执行。输出:1 4。注册 +4 到 microtask。 注册+2 +3 +5 到 macrotask。
microtask: 执行 +4 输出:5
macrotask: 执行 +2。 输出 2
microtask:
macrotask: 执行 +3。 输出 3
microtask:
macrotask: 执行 +5。 输出 6 7。 注册 +6 到 microtask。
microtask: 输出 8

所以总体输出的顺序为:1 4 5 2 3 6 7 8

如果这个输出与你所想相同,那么基本就没有问题了。
那么如果不对或者有问题怎么办?
Ähnlichkeiten, Unterschiede und Teilmechanismen von EventLoop zwischen Browsern und NodeJS

PS: 前面提到 【本次循环耗时】这个问题,这里我也不是非常清楚,望大牛指点。浏览器一般渲染页面60/S,以达到每秒60帧(60 fps),所以大概16ms一次,既然有了时间我们不经就会问?前面的任务处理耽误了则么办?因为javascript线程与UI线程互斥,某些任务导致 javascript引擎 坑了队友,自然而然没法在16ms的节点上到达这一步,从secrets of javascript ninja中了解到,一般会摒弃这次渲染,等待下一次循环。( 如有问题请指正! )

浏览器中的 event loop 到此结束,下面说说 NodeJS 的 event loop



二 NodeJS的event loop

NodeJS 的 event loop 也是有 Macrotask queue 与 Microtask queue 的。只不过 NodeJS 的略有不同。那么主要说说不同在哪里。

NodeJS中 Macrotask queue 与 Microtask queue 实例化到API为:

Macrotask queue --> script(主程序代码),setImmediate, I/O,setTimeout, setInterval

Microtask queue --> process.nextTick, Promise

1.Macrotask queue 不同之处

上面说到了浏览器 event loop 的 Macrotask queue 在每次循环中只会读取一个任务,NodeJS 中 Macrotask queue 会一次性读取完毕( 同阶段的执行完毕,后面会说到Macrotask queue 分为 6个阶段 ),然后向下读取Microtask。

注意: 这一条与 NodeJS版本有很大关系,在看 深入浅出NodeJS 这一本书时( 看的版本很旧,不知是否有修订版,如有请告知。 ),提到的 setImmediate 每次循环只会执行一次,并且给出的示例在 v8.9.1 版本跑时已不符合书中所写。书中示例如下(+ 为自定义标记,原文中没有):
+1 process.nextTick(function () {
       console.log('nextTick执行1');
   });

+2 process.nextTick(function () {
       console.log('nextTick执行2');
   });

+3 setImmediate(function () {
       console.log('setImmediateჽ执行1');

    +4 process.nextTick(function () {
           console.log('强势插入');
       });
   });

+5 setImmediate(function () {
       console.log('setImmediateჽ执行2');
   });

+6 console.log('正常执行');

正常执行
nextTick执行1
nextTick执行2
setImmediate执行1
强势插入
setImmediateჽ执行2

在 v8.9.1 中截图如下
Ähnlichkeiten, Unterschiede und Teilmechanismen von EventLoop zwischen Browsern und NodeJS

从图片中可以看到,至少在 v8.9.1 版本中 Macrotask queue 会直接全部执行。按照惯例从头到尾的梳理一遍

macrotask: javascript 代码,所有同步代码执行。输出:正常执行。注册 +3 +5 到 Macrotask。执行process.nextTick(),最终输出:正常执行, nextTick执行1, nextTick执行2。
  **microtask: 无
macrotask: 执行 +3 +5。 输出:setImmediate执行1, setImmediateჽ执行2。 执行process.nextTick(),最终输出:setImmediate执行1, setImmediateჽ执行2,强势插入。
microtask:

所以最终输出为:正常执行, nextTick执行1, nextTick执行2,setImmediate执行1, setImmediateჽ执行2,强势插入。


2.process.nextTick(),setImmediates,以及event loop的6个阶段

NodeJS 中 Macrotask queue会分为 6 个阶段,每个阶段的作用如下(process.nextTick()在6个阶段结束的时候都会执行):

timers:执行setTimeout() 和 setInterval()中到期的callback。

I/O callbacks:上一轮循环中有少数的I/Ocallback会被延迟到这一轮的这一阶段执行

idle, prepare:仅内部使用

poll:最为重要的阶段,执行I/O callback,在适当的条件下会阻塞在这个阶段

check:执行setImmediate的callback

close callbacks:执行close事件的callback,例如socket.on("close",func)
注:此6个阶段非笔者原创来自 https://cnodejs.org/topic/5a9...,文章从底层C代码分析NodeJS event loop。这里做只做简单整合。侵删。

在了解了这六个阶段后,我们可以发现定时器系列在NodeJS event loop中 Macrotask queue 读取顺序为:

1. setTimeout(fun,0) setInterval(fun,0) 
2. setImmediate

空口无凭,在实例中了解。的代码奉上( 代码较长,分为三段,方便阅读,避免滚动。 ):

+1 process.nextTick(function(){
    console.log("1");
});
+2 process.nextTick(function(){
    console.log("2");
    +3 setImmediate(function(){
        console.log("3");
    });
    +4 process.nextTick(function(){
        console.log("4");
    });
});

+5 setImmediate(function(){
    console.log("5");
    +6 process.nextTick(function(){
        console.log("6");
    });
    +7 setImmediate(function(){
        console.log("7");
    });
});
+8 setTimeout(e=>{
    console.log(8);
    +9 new Promise((resolve,reject)=>{
        console.log(8+"promise");
        resolve();
    }).then(e=>{
        console.log(8+"promise+then");
    })
},0)

+10 setTimeout(e=>{ console.log(9); },0)

+11 setImmediate(function(){
    console.log("10");
    +12 process.nextTick(function(){
        console.log("11");
    });
    +13 process.nextTick(function(){
        console.log("12");
    });
    +14 setImmediate(function(){
        console.log("13");
    });
});
console.log("14");

+15 new Promise((resolve,reject)=>{
    console.log(15);
    resolve();
}).then(e=>{
    console.log(16);
})

这么复杂的异步嵌套在一起是不是很头疼呢?
我!不!看!了!

Ähnlichkeiten, Unterschiede und Teilmechanismen von EventLoop zwischen Browsern und NodeJS

Das letzte Kämmen, das größte und vollständigste Kämmen. Seit der Antike sortieren Sie den

Makrotask: Javascript-Code von Anfang bis Ende, und alle synchronen Codes werden ausgeführt. Ausgabe: 14. Process.nextTick() ausführen, Endausgabe: 14, 15, 1, 2, 4. Registrieren Sie +3 +5 +8 +11 bei Macrotask. Melden Sie sich +15 bei Microtask an.
Mikroaufgabe: +15 Ausgabe 16 ausführen
Makroaufgabe: +8 +10 Ausgabe ausführen 8, 8Versprechen, 9. Melden Sie sich +9 bei Microtask an.
Mikrotask: +9 Ausgabe ausführen 8Versprechen+dann
Makrotask: +5 ausführen +11 +3 ausgeben 5, 10, 3. Registrieren Sie +7 +14 für Makrotask. Process.nextTick() ausführen, Endausgabe: 5 10 3 6 11 12.
Mikrotask: Keine
Makrotask: Ausführung +7 +14. Ausgabe: 7, 13
Mikrotask: Keine

Die endgültige Ausgabe ist: 14, 15, 1, 2, 4, 8, 8promise , 9, 8Versprechen+dann, 5, 10, 3, 6, 11, 12, 7, 13



Drei Enden

Das ist es. Die Browser- und NodeJS-Ereignisschleifen wurden alle analysiert. Dabei wurden einige Inhalte von Ruan Yifengs Blog, Zhihu und CSDN-Artikeln zitiert und gelöscht.

In letzter Zeit habe ich durch das Verstehen einiger Grundkenntnisse viel gewonnen. Dazu gehören für ... und alle möglichen seltsamen Fragen. Ich werde sie aufschreiben, wenn ich Zeit habe.

Das Obige ist der gesamte Inhalt dieses Artikels. Ich hoffe, er wird für das Studium aller hilfreich sein. Weitere verwandte Inhalte finden Sie auf der chinesischen PHP-Website.

Verwandte Empfehlungen:

Verwenden Sie Javascript, um den Browsertyp zu bestimmen

Verwenden Sie Node, um statische Dateidienste bereitzustellen

JS-Browser-Ereignisschleifenmechanismus

Das obige ist der detaillierte Inhalt vonÄhnlichkeiten, Unterschiede und Teilmechanismen von EventLoop zwischen Browsern und NodeJS. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn