浏览器
// 新版的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,到checksetTimeout(()=>{ 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'); })})复制代码