node运行机制&事件循环

node非阻塞模型

node运行机制的核心可以概括为非阻塞 ,我们都知道javascript是单线程的,不单单是指在浏览器环境中,在node环境中同样如此。

注:这里明确js的单线程的含义------在浏览器环境中,一个tab页对应一个renderer渲染进程,这个进程又包括了如GUI渲染线程、js引擎线程、计时器线程等多个线程,所以对于浏览器来说,js代码是由一个js引擎线程来执行的,即js是单线程的;在node环境下,一个node应用对应了一个进程,这个进程下负责执行js代码的也只有一个线程,即node环境下js也是单线程的。

简单举个单线程阻塞的例子:

javascript 复制代码
function a() {
    console.log('执行a函数');
}
function b() {
    while(true) {} // 无限循环阻塞了整个js执行线程的继续执行,a函数永远得不到执行
    a();
}
b();

node环境中的js之所以可以应对高并发的耗时操作(比如请求响应、数据库操作、IO)主要就归功于node的非阻塞机制

所谓非阻塞运行机制,概括来说就是将高耗时的操作"移出"js主线程(做异步处理,即交给异步模块处理),这样也就做到了不阻塞js主线程不断向下处理逻辑。 而那些高耗时的操作(相对于js主线程)后台执行,他们被异步模块所处理,异步模块又是多线程的,换句话说还是多线程处理高并发。

当js主线程的调用栈清空时,后台处理的异步操作按照一定的优先级顺序加入js主线程的调用栈来执行。这个优先级顺序不同于浏览器环境下的事件循环规则,而是node事件循环。

事件循环说白了就是js代码执行的一种机制,这种执行机制叫做"事件循环"。

node事件循环

简单回顾一下浏览器环境中的事件循环是什么样子的,如下demo:

javascript 复制代码
setTimeout(() => {
    console.log('callback');
}, 1000)
​
console.log("begin");
  1. 首先整个Task入栈(被js主线程执行),遇到setTimeout,将其交给异步模块处理(计时器线程)。
  1. 此时js主线程继续执行输出了begin,与js主线程并行的还有计时器线程中的计时任务,直至1s后,计时器线程将setTimeout的回调函数推入"宏任务队列"中去。
  2. js引擎线程(主线程)从宏任务队列中取出队头回调,输出callback

上面我们提到了"宏任务队列",当然还有"微任务队列",两者收集不同的回调并在不同时机执行,这里不多赘述。node事件循环与浏览器事件循环做对比,其实就两点差异:

  • 宏任务队列一分为三:Timer队列、Poll队列、Check队列,宏任务队列的本质不变,都是在js引擎线程空时从队列中取出新的回调入栈执行,只是说这三者对异步操作进行了更细的分类,分别收集不同异步操作的回调。

    Timer队列 :收集setTimeoutsetInterval这两个计时器的回调任务

    Poll队列 :收集文件IO数据库操作网络请求等耗时操作的回调(出队优先级高于其它两个队列

    Check队列 :收集setImmediate(node环境特有的api,也就是把回调立即加入队列)的回调。

  • 在微任务队列之前增加nextTick队列,收集process.nextTick的回调函数。

    (从宏任务队列中取出新的回调入栈执行的过程叫做一次TicknextTick就是在下一次Tick之前执行)

如上示意图,js调用栈空时接着执行nextTick队列中的任务(入栈执行),再者是微任务,最后在事件循环队列中取出下一个回调执行。

demo

javascript 复制代码
console.log('同步代码');
​
process.nextTick(() => {
    console.log('tick');
});
​
Promise.resolve().then(() => {
    console.log('promise');
});
​
setImmediate(() => {
    console.log('setImmediate');
})
​
// 同步代码 tick promise setImmediate

除了第一行直接输出之外,其它的都是异步任务,进入对应的队列,然后按顺序执行。

相关推荐
敲啊敲952717 分钟前
5.npm包
前端·npm·node.js
贵州晓智信息科技23 分钟前
如何优化求职简历从模板选择到面试准备
面试·职场和发展
CodeClimb27 分钟前
【华为OD-E卷-木板 100分(python、java、c++、js、c)】
java·javascript·c++·python·华为od
咸鱼翻面儿31 分钟前
Javascript异步,这次我真弄懂了!!!
javascript
brrdg_sefg32 分钟前
Rust 在前端基建中的使用
前端·rust·状态模式
m0_748230941 小时前
Rust赋能前端: 纯血前端将 Table 导出 Excel
前端·rust·excel
qq_589568101 小时前
Echarts的高级使用,动画,交互api
前端·javascript·echarts
黑客老陈2 小时前
新手小白如何挖掘cnvd通用漏洞之存储xss漏洞(利用xss钓鱼)
运维·服务器·前端·网络·安全·web3·xss
正小安2 小时前
Vite系列课程 | 11. Vite 配置文件中 CSS 配置(Modules 模块化篇)
前端·vite