浏览器和nodejs中的eventloop

浏览器和nodejs中的eventloop

浏览器中的Event Loop

在浏览器中,设计成为了单线程。如果要处理异步请求,则需要增加一层调度逻辑,把js代码封装成一个个的任务,放在一个任务队列中,主线程不断的读取任务执行。每次调取任务,都会创建新的调用栈

  • 宏任务: setTimeout,setInterval,requestAnimationFrarme,Ajax,fetch,script
  • 微任务: Promise.then,MutationObserver,Object.observe
    等微任务执行才能执行宏任务

Node.js中的Eventloop

nodejs是一个新的js运行环境。同时要支持异步逻辑,定时器,io,网络请求
Nodejs任务宏任务之间是有优先级的,定时器的Timer的逻辑比Io的逻辑高,close的优先级就很低。

  • 优先级: Timers, Pending, poll, check,close
  • Timers Callback:涉及到时间,越早执行越好
  • Pending Callback: 处理网络,io等异常的回调
  • Poll Callback: 处理io的data,网络的connection
  • check Callback: 执行setImmediate的回调,特点是刚执行完io之后就能回调这个
  • Close Callback: 关闭资源的回调,晚点执行也不影响
    Nodejs中的EventLoop每次是把当前优先级的所有宏任务跑完再去跑微任务,然后再去跑下一个优先级的宏任务

Node.js中的EventLoop的完整流程

  • Timer阶段: 执行一定数量的定时器,太多的话留到下次执行 setTimeout setInterval
  • 微任务: 执行所有的nextTick的微任务。再去执行其他的普通微任务
  • Pending阶段(I/Ocallback阶段): 执行一定数量的io和网络的异常回调,太多的话留到下次执行。处理一些上一轮循环中的少数未执行的io回调
  • 微任务: 执行所有nextTick的微任务,在执行其他的普通微任务
  • Idle/Prepare阶段: 内部的一个阶段
  • 微任务: 执行所有的nextTick微任务,然后执行其他的普通微任务
  • Poll阶段: 执行一定数量的文件的data回调,网络的connection回调,太多的放到下次执行,如果没有io回调并且没有timers,check阶段的回调处理,就阻塞在这里等待io时间
  • 微任务: 执行一定数量的setImmediate的callback,太多的留到下次执行
  • check阶段: 执行一定数量的setImmmediate的callback,太多的留到下次执行
  • 微任务: 执行一定数量的nextTick的微任务,在执行其他的普通微任务
  • close阶段: 执行一定数量的close事件的callback,太多的话留到下次执行
  • 微任务: 执行所有的nextTick的微任务,在执行其他的普通微任务
    如果执行到poll阶段,发现poll队列为空并且timers队列,check队列都没有执行,那么就阻塞在这里等待io事件
    在这里插入图片描述
  1. timer
    timers阶段会执行setTimeout和setInterval回调,最初是由poll阶段控制的,在node中的定时器也不是准确的事件,只能是尽快执行
  2. poll
    • 回到timer阶段执行回调
    • 执行io回调
    如果poll队列不为空,会遍历回调队列并同步执行,直到队列为空或者达到系统限制
    如果poll队列为空
        如果由setImmediate回调要执行,poll阶段会停止,然后进入到check阶段执行回调
        如果没有setImmediate回调需要执行,会等待回调并加入到队列中立即执行回调,需要由超时时间,防止一直等待下去
    
    当设定了timer而且poll队列为空,会判断timer是否超时,如果有的话timer阶段执行回调
  3. check阶段
    setImmediate()的回调会被加入到check队列中。
    console.log('start')
    setTimeout(() => {
        console.log('timer1')
        Promise.resolve().then(function() {
            console.log('promise1')
        })
    }, 0)
    setTimeout(() => {
        console.log('time2')
        Promise.resolve().then(function() {
            console.log('promise2')
        })
    }, 0)
    Promise.resolve().then(function() {
        console.log('promise3')
    })
    console.log('end')
    // start => end => promise3 => 
    
    一开始执行栈的同步任务,执行完毕后,打印出start end,讲两个timer放入timer队列,执行微任务,打印出promise3
    进入timers阶段,执行timer1的回调函数,打印timer1,然后Promise.then放入微任务队列,然后执行timer2,打印timer2,将promise.then()放入微任务队列。timer阶段有几个setTimeout/setInterval都会依次执行,并不像浏览器端,没执行一个宏任务之后就在去执行一个微任务。
  4. 注意
    setImmediate设计在poll阶段完成时执行,即check阶段
    setTimeout设置在poll阶段为空闲的时候,而且达到设定时间之后才会执行。但是在timer阶段执行
    在异步io内部调用的时候,总是先执行setImmediate,在执行setTimeout
    process.nextTick,这个函数独立于event loop之外,有一个自己的队列,当每个阶段完成后,如果存在nextTick队列,就会清空队列中的所有回调函数,并且由于其他的微任务队列先执行
    javascript最早就是用来写网页交互的逻辑,为了避免多线程同时修改dom的同步问题,所以被设计成为了单线程,解决了单线程的阻塞问题,加了一层调度逻辑,就是loop循环和task队列二,阻塞的线程放到其他的线程跑,支持了异步,为了支持高优先级的任务调度,引入了微任务队列,
  • 10
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值