实在不能忍了,记一下浏览器事件环与node事件环的区别

278 阅读1分钟

浏览器

// 新版的node 和 浏览器的效果完全一致  10之前
setTimeout(()=>{
    console.log('time1');
    Promise.resolve().then(data=>{
        console.log('p1')
    })
},0)
Promise.resolve().then(data=>{
    console.log('p2');
    setTimeout(()=>{
        console.log('time2');
    })
});
结果:p2、time1、p1、time2
// 当宏任务执行完毕后 会先清空微任务,微任务执行完后,会执行宏任务(只拿出一个来执行) 执行完后会再去清空微任务,无限循环
// 宏任务:ui线程  script脚本  setTimeout  setImmediate  MessageChannel 
// 微任务:then (内部的then执行顺序是优先于 setTimeout)  MutationObserver 

node事件环

五个阶段我们只关注其中三个

  • timer -》各种setTimout setInterval
  • poll -》各种fs文件读写的回调
  • check -》各种setImmediate

tips:微任务 promise process.nextTick(执行先于promise)

执行过程:

跟浏览器一样,主栈的代码执行完了后,先清空所有微任务,再进入timer阶段,拿出一个宏任务,再清空所有微任务,如此往复。 进入poll轮询阶段,如上清空fs的回调,如果check不为空,会进入check阶段,如果不为空,会停在poll阶段,等待其他阶段的回调达到执行的条件。

// eg1:  这两行不一定谁先,因为setTimeout一般是1-4ms,如果机器性能特别好,在4ms内,
// 执行完了主栈代码,那它就会跳过timer阶段,因为定时器没到时间
// 进而到poll,到check
setTimeout(()=>{
    console.log('timeout');
},0)
setImmediate(()=>{
    console.log('setImmidate');
})


// eg2: 无疑答案是:setImmidate、timeout
// 因为fs回调肯定是poll阶段,完了清空微任务后,因为check阶段的callback队列不为空,马上切到check执行
let fs = require('fs');
fs.readFile('./template.html',()=>{
    setTimeout(()=>{
        console.log('timeout');
    },5)
    setImmediate(()=>{
        console.log('setImmidate');
    })
})