Heim  >  Artikel  >  Web-Frontend  >  Detaillierte Erläuterung des Ereignisschleifenmechanismus des Javascript-Browsers

Detaillierte Erläuterung des Ereignisschleifenmechanismus des Javascript-Browsers

不言
不言nach vorne
2018-10-20 16:15:392412Durchsuche

Dieser Artikel bietet Ihnen eine detaillierte Erklärung des Ereignisschleifenmechanismus von JavaScript-Browsern. Ich hoffe, dass er für Freunde hilfreich ist.

Fragen vor uns:

Wie kann ein einzelner Thread asynchron sein?

Wie läuft die Ereignisschleife ab?

Was sind Makrotask und Mikrotask? und was sind sie? Was ist der Unterschied? ein einzelner Thread Asynchronität erreichen? Zuerst müssen wir die Beziehung zwischen einem einzelnen Thread und einem asynchronen Thread verstehen.

JS-Aufgaben werden in zwei Typen unterteilt: synchrone und asynchrone, und auch ihre Verarbeitungsmethoden sind unterschiedlich. Synchrone Aufgaben werden direkt zur Ausführung im Hauptthread eingereiht, während asynchrone Aufgaben in die Aufgabenwarteschlange gestellt werden In der Aufgabenwarteschlange müssen mehrere Aufgaben (asynchrone Aufgaben) in die Warteschlange gestellt werden. Die Aufgabenwarteschlange ähnelt einem Puffer. Die Aufgabe wird im nächsten Schritt in den Aufrufstapel (Call Stack) und dann in die Hauptwarteschlange verschoben Der Thread führt die Aufgabe des Aufrufstapels aus. Einzelner Thread bedeutet, dass es in der JS-Engine nur einen Thread (Hauptthread) gibt, der für das Parsen und Ausführen von JS-Code verantwortlich ist, das heißt, er kann jeweils nur eine Sache ausführen, und das wissen wir Bei einer Ajax-Anfrage wartet der Hauptthread auf seine Antwort. Gleichzeitig wird der Browser die Ajax-Rückruffunktion in der Ereignistabelle registrieren. Nachdem die Antwort zurückkommt, wird die Rückruffunktion hinzugefügt Die Aufgabe wird in die Warteschlange gestellt und wartet auf die Ausführung. Dadurch wird keine Thread-Blockierung verursacht, sodass die Art und Weise, wie js Ajax-Anfragen verarbeitet, asynchron ist.

Kurz gesagt, der Prozess der Überprüfung, ob der Aufrufstapel leer ist und der Bestimmung, welche Aufgabe zum Aufrufstapel hinzugefügt werden soll, ist die Ereignisschleife, und der Kern der asynchronen Implementierung von js ist die Ereignisschleife.

Aufrufstapel und Aufgabenwarteschlange

Wie der Name schon sagt, ist der Aufrufstapel eine Stapelstruktur. Funktionsaufrufe bilden einen Stapelrahmen, der Kontextinformationen wie Parameter und lokale Variablen enthält Aktuell ausgeführte Funktion Nachdem die Funktion ausgeführt wurde, wird ihr Ausführungskontext vom Stapel entfernt.

Das folgende Bild zeigt die Beziehung zwischen dem Aufrufstapel und der Aufgabenwarteschlange

Ereignisschleife

Detaillierte Erläuterung des Ereignisschleifenmechanismus des Javascript-BrowsersÜber die Ereignisschleife, Einführung in HTML-Spezifikationen

Es muss mindestens eine Ereignisschleife pro Benutzeragent vorhanden sein, und höchstens eine Ereignisschleife pro Einheit verwandter Suchkontexte ähnlichen Ursprungs.Eine Ereignisschleife verfügt über eine oder mehrere Aufgabenwarteschlangen.Jede Aufgabe ist so definiert, dass sie von einer bestimmten Aufgabenquelle stammt.

Verstanden aus dem Spezifikation: Der Browser verfügt über mindestens eine Ereignisschleife und jede Ereignisschleife verfügt über mindestens eine Aufgabenwarteschlange (Makrotask). Jede externe Aufgabe verfügt über eine eigene Gruppe, und der Browser legt Prioritäten für verschiedene Aufgabengruppen fest.

Makrotask und Mikrotask

Die Spezifikation erwähnt zwei Konzepte, führt sie jedoch nicht im Detail ein. Nach Rücksprache mit einigen Informationen kann sie wie folgt zusammengefasst werden:

Makrotask: enthält der js-Code, der das gesamte ausführt, Ereignisrückrufe, XHR-Rückrufe, Timer (setTimeout/setInterval/setImmediate), IO-Operationen, UI-Rendering

Mikrotask: Aufgaben, die den Anwendungsstatus aktualisieren, einschließlich Versprechensrückrufe, MutationObserver, Prozess. nextTick, Object.observe

Darunter sind setImmediate undprocess.nextTick die Implementierung von nodejs, die im Artikel zu nodejs ausführlich vorgestellt wird.

Ereignisverarbeitungsprozess

Was das Verständnis von Makrotask und Mikrotask betrifft, mag es aus dieser Sicht etwas unklar sein, in Kombination mit dem Ereignismechanismus ist es jedoch viel klarer Das folgende Bild kann als Einführung bezeichnet werden.

Zusammenfassend umfassen die Schritte einer Ereignisschleife:

1. Überprüfen Sie, ob die Makrotask-Warteschlange leer ist leer, gehen Sie zu 2, was bedeutet: Wenn leer, gehen Sie zu 3Detaillierte Erläuterung des Ereignisschleifenmechanismus des Javascript-Browsers2. Führen Sie eine Aufgabe in der Makrotask aus.
3 Überprüfen Sie weiterhin, ob die Mikrotask-Warteschlange leer ist. Wenn ja, gehen Sie zu 4, andernfalls gehen Sie zu 5

4. Nehmen Sie die Aufgabe in der Mikrotask heraus, führen Sie sie aus und kehren Sie zu Schritt 3 zurück.

5. Führen Sie eine Ansichtsaktualisierung durch


Ausführungsreihenfolge von Mactotask und Mikrotask



Nachdem ich so viel trockenes Zeug gelesen habe. Um das Konzept vorzustellen, warum schauen Sie sich nicht einen Code an, um es zu erleben?

console.log('start')
setTimeout(function() {
console.log('setTimeout')
}, 0)
Promise.resolve().then(function() {
console.log('promise1')
}).then(function() {
console.log('promise2')
})
console.log('end')

Wie lautet die Protokollsequenz, die von der Druckstation ausgegeben wird? Basierend auf der Analyse der obigen Schritte ist es so einfach~

Detaillierte Erläuterung des Ereignisschleifenmechanismus des Javascript-Browsers

Zuerst wird der globale Code (main()) zur Ausführung in den Aufrufstapel verschoben und gestartet wird gedruckt;

Als nächstes wird setTimeout in die Makrotask-Warteschlange verschoben, Promise.then Callback wird in die Mikrotask-Warteschlange gestellt und schließlich wird console.log('end') ausgeführt, um end; auszudrucken

Zu diesem Zeitpunkt wurde der Code im Aufrufstapel ausgeführt. Wenn wir auf die Definition der Makrotask zurückblicken, wissen wir, dass der globale Code zur Makrotask gehört die Mikrotask-Warteschlange. Führen Sie den Promise-Callback aus und drucken Sie Promise1

promise回调函数默认返回undefined,promise状态变为fullfill触发接下来的then回调,继续压入microtask队列,event loop会把当前的microtask队列一直执行完,此时执行第二个promise.then回调打印出promise2;

这时microtask队列已经为空,从上面的流程图可以知道,接下来主线程会去做一些UI渲染工作(不一定会做),然后开始下一轮event loop,执行setTimeout的回调,打印出setTimeout;

这个过程会不断重复,也就是所谓的事件循环。

视图渲染的时机

回顾上面的事件循环示意图,update rendering(视图渲染)发生在本轮事件循环的microtask队列被执行完之后,也就是说执行任务的耗时会影响视图渲染的时机。通常浏览器以每秒60帧(60fps)的速率刷新页面,据说这个帧率最适合人眼交互,大概16.7ms渲染一帧,所以如果要让用户觉得顺畅,单个macrotask及它相关的所有microtask最好能在16.7ms内完成。

但也不是每轮事件循环都会执行视图更新,浏览器有自己的优化策略,例如把几次的视图更新累积到一起重绘,重绘之前会通知requestAnimationFrame执行回调函数,也就是说requestAnimationFrame回调的执行时机是在一次或多次事件循环的UI render阶段。

以下代码可以验证

setTimeout(function() {console.log('timer1')}, 0)
requestAnimationFrame(function(){
	console.log('requestAnimationFrame')
	})
	setTimeout(function() {console.log('timer2')}, 0)
	new Promise(function executor(resolve) {
	console.log('promise 1')
	resolve()
	console.log('promise 2')
	}).then(function() {
	console.log('promise then')
	})
	console.log('end')

Detaillierte Erläuterung des Ereignisschleifenmechanismus des Javascript-Browsers

Detaillierte Erläuterung des Ereignisschleifenmechanismus des Javascript-Browsers

可以看到,结果1中requestAnimationFrame()是在一次事件循环后执行,而在结果2,它的执行则是在三次事件循环结束后。

总结

1、事件循环是js实现异步的核心

2、每轮事件循环分为3个步骤:

a) 执行macrotask队列的一个任务
b) 执行完当前microtask队列的所有任务
c) UI render

3、浏览器只保证requestAnimationFrame的回调在重绘之前执行,没有确定的时间,何时重绘由浏览器决定

Das obige ist der detaillierte Inhalt vonDetaillierte Erläuterung des Ereignisschleifenmechanismus des Javascript-Browsers. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

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