Heim  >  Artikel  >  Web-Frontend  >  In diesem Artikel erfahren Sie mehr über die Timer-Warteschlange in der Knotenereignisschleife

In diesem Artikel erfahren Sie mehr über die Timer-Warteschlange in der Knotenereignisschleife

青灯夜游
青灯夜游nach vorne
2023-04-14 15:10:251432Durchsuche

In diesem Artikel erfahren Sie mehr über die Timer-Warteschlange in der Knotenereignisschleife

Im vorherigen Artikel haben wir die Mikrotask-Warteschlange und ihre Prioritätsreihenfolge innerhalb jeder Warteschlange besprochen. In diesem Artikel besprechen wir Timer-Warteschlangen, eine weitere Warteschlange in Node.js für die Verarbeitung von asynchronem Code.

Bevor wir uns mit Timer-Warteschlangen befassen, werfen wir einen kurzen Blick auf die Mikrotask-Warteschlangen. Um die Rückruffunktion in die Mikrotask-Warteschlange einzureihen, verwenden wir Funktionen wie process.nextTick() und Promise.resolve(). Microtask-Warteschlangen haben die höchste Priorität, wenn es um die Ausführung von asynchronem Code in Node.js geht. [Empfohlene verwandte Tutorials: nodejs-Video-Tutorialprocess.nextTick()Promise.resolve() 等函数。当涉及到执行 Node.js 中的异步代码时,微任务队列具有最高优先级。【相关教程推荐:nodejs视频教程编程教学

入队回调函数

现在我们转到计时器队列。要将回调函数排入计时器队列,我们可以使用 setTimeoutsetInterval等函数。为了方便说明,本文将使用 setTimeout

为了理解计时器队列的执行顺序,我们会进行一系列实验,在微任务队列和计时器队列中入队任务。

实验三

代码

// index.js
setTimeout(() => console.log("this is setTimeout 1"), 0);
setTimeout(() => console.log("this is setTimeout 2"), 0);
setTimeout(() => console.log("this is setTimeout 3"), 0);

process.nextTick(() => console.log("this is process.nextTick 1"));
process.nextTick(() => {
  console.log("this is process.nextTick 2");
  process.nextTick(() =>
    console.log("this is the inner next tick inside next tick")
  );
});
process.nextTick(() => console.log("this is process.nextTick 3"));

Promise.resolve().then(() => console.log("this is Promise.resolve 1"));
Promise.resolve().then(() => {
  console.log("this is Promise.resolve 2");
  process.nextTick(() =>
    console.log("this is the inner next tick inside Promise then block")
  );
});
Promise.resolve().then(() => console.log("this is Promise.resolve 3"));

译注:大家不用紧张,这段代码就是在上篇“福利实验”的基础上,在开头加了 3 个 setTimeout 语句。

该代码包含三个 process.nextTick() 的调用,三个 Promise.resolve() 的调用和三个 setTimeout 的调用。每个回调函数记录适当的消息。所有三个 setTimeout 调用都有 0ms 的延迟,这表示在执行每个 setTimeout 语句时,回调函数都立即入队到计时器队列等待。第二次 process.nextTick() 和第二次 Promise.resolve() 都有一个额外的 process.nextTick() 语句,并且每个都带有一个回调函数。

可视化

In diesem Artikel erfahren Sie mehr über die Timer-Warteschlange in der Knotenereignisschleife

当调用栈执行所有语句后,在 nextTick 队列中有 3 个回调,在 Promise 队列中有 3 个回调,在计时器队列中也有 3 个回调。没有代码要执行,控制权进入事件循环。

nextTick 队列具有最高优先级,其次是 Promise 队列,然后是计时器队列。从 nextTick 队列中获取第1 个回调并执行它,将一条消息记录到控制台。接着获取第 2 个回调并执行它,这也会记录一条消息。第 2 个回调包含 process.nextTick() 的调用,该方法将新的回调添加到了 nextTick 队列中。继续执行,并获取和执行第 3 个回调以及记录一条消息。最后,我们将新添加到 nextTick 队列的回调函数取出并在调用栈中执行,从而在控制台上输出了第四条日志信息。

当 nextTick 队列为空时,事件循环转向 Promise 队列。从队列中获取第 1 个回调,在控制台打印一条信息,第二个回调效果类似,并且还向 nextTick 队列添加了一个回调。 Promise 中的第 3 个回调被执行,接着日志消息被输出。此时 Promise 队列已空,事件循环检查 nextTick 队列是否存在新的回调,找到之后同样将消息记录到控制台。

现在,两个微任务队列都空了,事件循环转向计时器队列。我们有三个回调,每个回调依次从计时器队列中取出并在调用栈上执行,将分别打印 "setTimeout 1"、"setTimeout 2" 和 "setTimeout 3"。

this is process.nextTick 1
this is process.nextTick 2
this is process.nextTick 3
this is the inner next tick inside next tick
this is Promise.resolve 1
this is Promise.resolve 2
this is Promise.resolve 3
this is the inner next tick inside Promise then block
this is setTimeout 1
this is setTimeout 2
this is setTimeout 3

推论

微任务队列中的回调函数会在定时器队列中的回调函数之前执行。

到目前为止,优先顺序是 nextTick 队列,其次是 Promise 队列,然后是定时器队列。现在让我们继续进行下一个实验。

实验四

// index.js
setTimeout(() => console.log("this is setTimeout 1"), 0);
setTimeout(() => {
  console.log("this is setTimeout 2");
  process.nextTick(() =>
    console.log("this is inner nextTick inside setTimeout")
  );
}, 0);
setTimeout(() => console.log("this is setTimeout 3"), 0);

process.nextTick(() => console.log("this is process.nextTick 1"));
process.nextTick(() => {
  console.log("this is process.nextTick 2");
  process.nextTick(() =>
    console.log("this is the inner next tick inside next tick")
  );
});
process.nextTick(() => console.log("this is process.nextTick 3"));

Promise.resolve().then(() => console.log("this is Promise.resolve 1"));
Promise.resolve().then(() => {
  console.log("this is Promise.resolve 2");
  process.nextTick(() =>
    console.log("this is the inner next tick inside Promise then block")
  );
});
Promise.resolve().then(() => console.log("this is Promise.resolve 3"));

第四个实验的代码大部分与第三个相同,只有一个例外。传递给第二个 setTimeout 函数的回调函数现在包含 process.nextTick(), Programmierunterricht

Rückruffunktion in die Warteschlange stellen

Jetzt gehen wir zur Timer-Warteschlange über. Um eine Rückruffunktion in eine Timer-Warteschlange einzureihen, können wir Funktionen wie setTimeout und setInterval verwenden. Zur Vereinfachung der Erklärung wird in diesem Artikel setTimeout verwendet.

assets_YJIGb4i01jvw0SRdL5Bt_c4034ba006d840128b729005183abdf4_compressed (1).gifUm die Ausführungsreihenfolge der Timer-Warteschlange zu verstehen, führen wir eine Reihe von Experimenten durch, um Aufgaben in die Mikrotask-Warteschlange und die Timer-Warteschlange einzureihen.

#🎜🎜#Experiment Drei#🎜🎜#

#🎜🎜#code#🎜🎜 ##🎜🎜#
this is process.nextTick 1
this is process.nextTick 2
this is process.nextTick 3
this is the inner next tick inside next tick
this is Promise.resolve 1
this is Promise.resolve 2
this is Promise.resolve 3
this is the inner next tick inside Promise then block
this is setTimeout 1
this is setTimeout 2
this is inner nextTick inside setTimeout
this is setTimeout 3
#🎜🎜# Übersetzungshinweis: Seien Sie nicht nervös, dieser Code basiert auf dem vorherigen „Wohlfahrtsexperiment“, wobei am Anfang drei setTimeout-Anweisungen hinzugefügt wurden. #🎜🎜#
#🎜🎜#Dieser Code enthält drei Aufrufe von process.nextTick(), drei Aufrufe von Promise.resolve() und drei A-Aufrufe zu setTimeout. Jede Rückruffunktion protokolliert die entsprechende Nachricht. Alle drei setTimeout-Aufrufe haben eine Verzögerung von 0 ms, was bedeutet, dass die Rückruffunktion sofort in die Warteschlange des Timers gestellt wird, wenn jede setTimeout-Anweisung ausgeführt wird. Der Server Warteschlange wartet. Der zweite process.nextTick() und der zweite Promise.resolve() haben beide eine zusätzliche process.nextTick()-Anweisung, und jede kommt mit einer Callback-Funktion. #🎜🎜#

#🎜🎜#Visualisierung#🎜🎜##🎜🎜##🎜🎜#In diesem Artikel erfahren Sie mehr über die Timer-Warteschlange in der Knotenereignisschleife# 🎜 🎜##🎜🎜#Wenn der Aufrufstapel alle Anweisungen ausführt, sind im nextTick 3 vorhanden Warteschlange Es gibt 3 Rückrufe in der Promise-Warteschlange und 3 Rückrufe in der Timer-Warteschlange. Es muss kein Code ausgeführt werden und die Steuerung wird an die Ereignisschleife übergeben. #🎜🎜##🎜🎜#nextTick-Warteschlange hat die höchste Priorität, gefolgt von der Promise-Warteschlange und dann der Timer-Warteschlange. Holen Sie sich den ersten Rückruf aus der nextTick-Warteschlange, führen Sie ihn aus und protokollieren Sie eine Nachricht an der Konsole. Holen Sie sich dann den zweiten Rückruf und führen Sie ihn aus, wodurch auch eine Nachricht protokolliert wird. Der zweite Rückruf enthält einen Aufruf von process.nextTick(), der der nextTick-Warteschlange einen neuen Rückruf hinzufügt. Setzen Sie die Ausführung fort und rufen Sie den dritten Rückruf ab, führen Sie ihn aus und protokollieren Sie eine Nachricht. Abschließend nehmen wir die neu zur nextTick-Warteschlange hinzugefügte Callback-Funktion heraus, führen sie im Call-Stack aus und geben so die vierte Log-Nachricht auf der Konsole aus. #🎜🎜##🎜🎜#Wenn die nextTick-Warteschlange leer ist, wechselt die Ereignisschleife zur Promise-Warteschlange. Holen Sie sich den ersten Rückruf aus der Warteschlange und geben Sie eine Nachricht an die Konsole aus. Der zweite Rückruf hat einen ähnlichen Effekt und fügt auch einen Rückruf zur nextTick-Warteschlange hinzu. Der dritte Rückruf im Promise wird ausgeführt und die Protokollmeldung ausgegeben. Zu diesem Zeitpunkt ist die Promise-Warteschlange leer und die Ereignisschleife überprüft die nextTick-Warteschlange, um festzustellen, ob ein neuer Rückruf vorliegt. Sobald die Nachricht gefunden wird, wird sie auch in der Konsole protokolliert. #🎜🎜##🎜🎜# Jetzt sind beide Mikrotask-Warteschlangen leer und die Ereignisschleife bewegt sich in die Timer-Warteschlange. Wir haben drei Rückrufe, von denen jeder aus der Timer-Warteschlange entnommen und auf dem Aufrufstapel ausgeführt wird und jeweils „setTimeout 1“, „setTimeout 2“ und „setTimeout 3“ ausgibt. #🎜🎜#
// index.js
setTimeout(() => console.log("this is setTimeout 1"), 1000);
setTimeout(() => console.log("this is setTimeout 2"), 500);
setTimeout(() => console.log("this is setTimeout 3"), 0);

#🎜🎜#Inferenz#🎜🎜##🎜🎜#
#🎜🎜#Die Rückruffunktion in der Mikrotask-Warteschlange befindet sich in der Timer-Warteschlange Die Callback-Funktion wird zuvor ausgeführt. #🎜🎜#
#🎜🎜#Bisher ist die Priorität die nextTick-Warteschlange, gefolgt von der Promise-Warteschlange und dann der Timer-Warteschlange. Kommen wir nun zum nächsten Experiment. #🎜🎜#

#🎜🎜#Experiment vier#🎜🎜#

this is setTimeout 3
this is setTimeout 2
this is setTimeout 1
#🎜🎜#Der Code des vierten Experiments ist größtenteils der gleiche wie der dritte, nur eine Ausnahme. Die an die zweite Funktion setTimeout übergebene Rückruffunktion enthält jetzt einen Aufruf von process.nextTick(). #🎜🎜##🎜🎜##🎜🎜#Visualisierung#🎜🎜##🎜🎜##🎜🎜##🎜🎜##🎜🎜#

让我们应用从之前的实验中学到的知识,快进到回调在微任务队列中已经被执行的点。假设我们有三个回调在计时器队列中排队等待。第一个回调出队并在调用堆栈上执行,“setTimeout 1”消息打印到控制台。事件循环继续运行第二个回调,“setTimeout 2”消息打印到控制台。同时,也会有一个回调函数入队了 nextTick 队列。

在执行计时器队列中的每个回调后,事件循环会返回检查微任务队列。检查 nextTick 队列确定需要执行的回调函数。这时第二个 setTimeout 推入的回调函数出队并在调用栈上执行,结果“inner nextTick”消息打印到控制台。

现在微任务队列为空了,控制权返回到计时器队列,最后一个回调被执行,控制台上显示消息“setTimeout 3”。

this is process.nextTick 1
this is process.nextTick 2
this is process.nextTick 3
this is the inner next tick inside next tick
this is Promise.resolve 1
this is Promise.resolve 2
this is Promise.resolve 3
this is the inner next tick inside Promise then block
this is setTimeout 1
this is setTimeout 2
this is inner nextTick inside setTimeout
this is setTimeout 3

推论

微任务队列中的回调函数会在定时器队列中的回调函数执行之间被执行。

实验五

代码

// index.js
setTimeout(() => console.log("this is setTimeout 1"), 1000);
setTimeout(() => console.log("this is setTimeout 2"), 500);
setTimeout(() => console.log("this is setTimeout 3"), 0);

该代码包含三个 setTimeout 语句,包含三个不同的、入队时机不一样的回调函数。第一个 setTimeout 延迟 1000 毫秒,第二个延迟 500 毫秒,第三个延迟 0 毫秒。当执行这些回调函数时,它们只是简单地将一条消息记录到控制台中。

可视化

由于代码片段的执行非常简单,因此我们将跳过可视化实验。当多个 setTimeout 调用被发出时,事件循环首先排队最短延迟的一个并在其他之前执行。结果,我们观察到“setTimeout 3”先执行,然后是“setTimeout 2”,最后是“setTimeout 1”。

this is setTimeout 3
this is setTimeout 2
this is setTimeout 1

推论

计时器队列回调按照先进先出(FIFO)的顺序执行。

总结

实验表明,微任务队列中的回调比定时器队列中的回调具有更高优先级,并且微任务队列中的回调在定时器队列中的回调之间执行。定时器队列遵循先进先出(FIFO)顺序。

原文链接:Visualizing The Timer Queue in Node.js Event Loop,2023年4月4日,by Vishwas Gopinath

更多node相关知识,请访问:nodejs 教程

Das obige ist der detaillierte Inhalt vonIn diesem Artikel erfahren Sie mehr über die Timer-Warteschlange in der Knotenereignisschleife. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

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