Node中的事件轮询机制

2 node中的事件循环模型

2-1 一些属性

  • setInterval():----循环定时器

  • setTimeout();—延迟定时器

  • setImmendiate(); —立即执行函数

  • clearInterval();----清除循环定时器

  • clearTimeout();----清除演示定时器

  • clearImmendiate;----清除立即执行函数

/*立即执行函数*/

setImmediate(()=>{
    console.log('我是异步执行的立即执行函数的回调函数');
})

console.log('我是同步执行的任务');

//我是同步执行的任务
// 我是异步执行的立即执行函数的回调函数

//	执行结果与异步执行结果并无两样

setImmendiate即立即执行函数,
和setTimeout(()=>{})类似,虽然是立即到了执行时间,但因为是异步回调,最后的结果仍然是等主线程上的任务清空时,在执行回调

2-2 循环模型

  • 1 在node中有一种类似于js运行时的事件循环机制----事件轮询
  • 2 在主线程上的代码被清空时,node的事件轮询机制就会开启
  • 3 在轮询的过程中回调队列(消息队列)上若是有正在等待执行的回调函数,那么事件轮询将会对其进行相应的处理,若是没有回调函数正在等待执行,那么事件轮询将被挂起等待

node事件循环总共有六个阶段

  • 第一个阶段:timers

    定时器阶段:1 开始计时

    ​ 2 执行定时器的回调(setInterval,setTimeout)


  • 第二个阶段:pending callbacks

    系统阶段


  • 第三个阶段:idle prepare

    准备阶段


  • 第四个阶段:poll(核心)

    事件轮询阶段

1> 从队列里取出回调函数(除了定时器的回调),并同步执行,直到回调队列为空时,或者达到系统最大限度。

2> 如果回调队列为空时,继续判断是否有设置过setImmendiate

​ 1) 有设置过则进入下一个check阶段,这个阶段是专门用于执行setimmediate所在设置的回调。

​ 2) 没有则在此阶段停留,等待回调函数被插入回调队列。若这时有定时器的回调准备执行了,那么进入check阶段,目的:为了走第五个阶段,随后走第六个阶段,循环到第一阶段,执行定时器中的回调


  • 第五个阶段:check —专门用于执行setImmediate所设置的回调

  • 第六个阶段:close callbacks

关闭回调阶段


process.nextTick()函数

  • 能在任意阶段优先执行----除了主线程阶段

  • 用于设置立即执行函数

  • 和setImmendiate()类似

  • process.nextTick(()=>{});

    /*立即执行函数*/
    setImmediate(function () {
        console.log('我是异步执行的立即执行函数的回调函数');
    });
    console.log('我是同步执行的任务');
    //我是同步执行的任务
    // 我是异步执行的立即执行函数的回调函数
    process.nextTick(function () {
        console.log('这是process.nextTick()函数钩子执行的回调函数,并且执行了');
    });
    console.log('我是同步执行的任务2');
    
    // 我是同步执行的任务
    // 我是同步执行的任务2
    // 这是process.nextTick()函数钩子执行的回调函数,并且执行了
    // 我是异步执行的立即执行函数的回调函数
    

注意:

setTimeout(()=>{console.log('setTimeout')});

setImmediate(()=>{console.log('setImmediate')});

按照事件轮询模型,这里的输出应当是

setImmediate
setTimeout

但是在实际执行过程中我们发现它们的执行顺序前后都不一定

原因:在执行的过程中,如果事件轮询速度快过于定时器计时速度,那么先执行setImmediate,然后再执行setTimeout.

若事件轮询的速度慢于计时器计时,那么先执行setTimeout,在执行setImmediate

setTimeout(()=>{console.log('setTimeout')});

setImmediate(()=>{console.log('setImmediate')});

console.log('同步');

在代码里添加了同步任务,这里的执行结果又和之前的代码不一样了。执行顺序一直是 先setTimeout,再setImmediate

原因:因为主线程在执行的过程,setTimeout(()=>{})完成,且因为主线程执行过程中轮询机制并未开始轮询,所以在第一阶段setTimeout(()=>{})就已经执行了。


实例

console.log('1');

setImmediate(() => {
    console.log('2');
});

setTimeout(() => {
    console.log('3');
})

setTimeout(() => {
    console.log('4')
}, 1000);

console.log('5');

// 1
// 5
// 3
// 2
// 4
// 解释
// 先执行同步任务,定时器开始计时完成后挂起回调,异步任务推到消息队列等待主线程执行完成
// 输出 1 5
// 主线程执行完成,无同步任务,于是开启事件轮询
// 在第一阶段中发现定时器的回调待执行,于是执行定时器的回调,
// 输出 3
// 进入第二,三阶段
// 进入第四阶段,发现回调队列为空(1s回调的定时器时长中,事件轮询已经执行很多次),判断是否有
// setImmediate,发现有,则将其推入第六个阶段执行,
// 进入第六个阶段,发现上个阶段的setImmediate有回调函数,执行回调函数
// 输出 2
// 进入第一个阶段,发现没有定时器执行完毕返回回调(定时器未完成)
// 进入第2,3,4阶段
// 发现回调队列没有任务,此时事件轮询将在此处停留等待
// 若此时1s定时器回调函数准备执行了,那么事件轮询将进入check阶段,然后到第一个阶段执行定时器回调
// 输出 4
// 进入 2,3,4阶段,发现回调队列无任务,无setImmendiate,无准备执行的定时器回调,轮询将被停留

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值