一文带你了解Node事件循环中的计时器队列
在 上一篇文章 中,我们探讨了微任务队列及它在各队列中的优先级顺序。在本文,我们将讨论计时器队列,这是 Node.js中用于处理异步代码的另一个队列。
在深入研究计时器队列之前,让我们快速回顾一下微任务队列。为了将回调函数排入微任务队列,我们使用诸如 process.nextTick()
和 Promise.resolve()
等函数。当涉及到执行 Node.js 中的异步代码时,微任务队列具有最高优先级。【相关教程推荐:nodejs视频教程、编程教学】
入队回调函数
现在我们转到计时器队列。要将回调函数排入计时器队列,我们可以使用 setTimeout
和 setInterval
等函数。为了方便说明,本文将使用 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()
语句,并且每个都带有一个回调函数。
可视化
当调用栈执行所有语句后,在 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()
的调用。
可视化
让我们应用从之前的实验中学到的知识,快进到回调在微任务队列中已经被执行的点。假设我们有三个回调在计时器队列中排队等待。第一个回调出队并在调用堆栈上执行,“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 教程!
以上是一文带你了解Node事件循环中的计时器队列的详细内容。更多信息请关注PHP中文网其他相关文章!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

热门话题

PHP与Vue:完美搭档的前端开发利器在当今互联网高速发展的时代,前端开发变得愈发重要。随着用户对网站和应用的体验要求越来越高,前端开发人员需要使用更加高效和灵活的工具来创建响应式和交互式的界面。PHP和Vue.js作为前端开发领域的两个重要技术,搭配起来可以称得上是完美的利器。本文将探讨PHP和Vue的结合,以及详细的代码示例,帮助读者更好地理解和应用这两

在前端开发面试中,常见问题涵盖广泛,包括HTML/CSS基础、JavaScript基础、框架和库、项目经验、算法和数据结构、性能优化、跨域请求、前端工程化、设计模式以及新技术和趋势。面试官的问题旨在评估候选人的技术技能、项目经验以及对行业趋势的理解。因此,应试者应充分准备这些方面,以展现自己的能力和专业知识。

JavaScript教程:如何获取HTTP状态码,需要具体代码示例前言:在Web开发中,经常会涉及到与服务器进行数据交互的场景。在与服务器进行通信时,我们经常需要获取返回的HTTP状态码来判断操作是否成功,根据不同的状态码来进行相应的处理。本篇文章将教你如何使用JavaScript获取HTTP状态码,并提供一些实用的代码示例。使用XMLHttpRequest

Django是一个Python编写的web应用框架,它强调快速开发和干净方法。尽管Django是一个web框架,但是要回答Django是前端还是后端这个问题,需要深入理解前后端的概念。前端是指用户直接和交互的界面,后端是指服务器端的程序,他们通过HTTP协议进行数据的交互。在前端和后端分离的情况下,前后端程序可以独立开发,分别实现业务逻辑和交互效果,数据的交

Go语言作为一种快速、高效的编程语言,在后端开发领域广受欢迎。然而,很少有人将Go语言与前端开发联系起来。事实上,使用Go语言进行前端开发不仅可以提高效率,还能为开发者带来全新的视野。本文将探讨使用Go语言进行前端开发的可能性,并提供具体的代码示例,帮助读者更好地了解这一领域。在传统的前端开发中,通常会使用JavaScript、HTML和CSS来构建用户界面

Django:前端和后端开发都能搞定的神奇框架!Django是一个高效、可扩展的Web应用程序框架。它能够支持多种Web开发模式,包括MVC和MTV,可以轻松地开发出高质量的Web应用程序。Django不仅支持后端开发,还能够快速构建出前端的界面,通过模板语言,实现灵活的视图展示。Django把前端开发和后端开发融合成了一种无缝的整合,让开发人员不必专门学习

Golang与前端技术结合:探讨Golang如何在前端领域发挥作用,需要具体代码示例随着互联网和移动应用的快速发展,前端技术也愈发重要。而在这个领域中,Golang作为一门强大的后端编程语言,也可以发挥重要作用。本文将探讨Golang如何与前端技术结合,以及通过具体的代码示例来展示其在前端领域的潜力。Golang在前端领域的作用作为一门高效、简洁且易于学习的

JavaScript中的HTTP状态码获取方法简介:在进行前端开发中,我们常常需要处理与后端接口的交互,而HTTP状态码就是其中非常重要的一部分。了解和获取HTTP状态码有助于我们更好地处理接口返回的数据。本文将介绍使用JavaScript获取HTTP状态码的方法,并提供具体代码示例。一、什么是HTTP状态码HTTP状态码是指当浏览器向服务器发起请求时,服务
