有以下demo,最终控制台会输入的内容是啥
setTimeout(()=>{console.log("timer1")Promise.resolve(1).then(()=>{console.log("promise1")})console.log("timer 1normal")})setTimeout(()=>{console.log("timer2")})console.log("primary")
因为1是主流程代码,2是宏任务里面的代码啊🤔
因为3是主流程代码啊,4是微任务里面的代码🤔
好像这样开始有点迷茫了~~,3和4不是都在宏任务里面的么。
得有【宏任务队列和微任务队列】这些概念才能更好理解代码
var macroTask = [];//宏任务var microTask = [];//微任务var timer;//事件轮训的定时器window.setTimeoutx = function (cb) {macroTask.push(cb);}//模拟Promise.resolve(1).thenwindow.micpush = function (cb) {microTask.push(cb);}var eventLoop = function () {clearTimeout(timer);//这块代码是为了演示作用,正常环境不会有==========【if (macroTask.length || microTask.length) {console.warn("macroTask", macroTask, 'microTask', microTask)}else {console.warn("宏任务和微任务队列为空")}//这块代码是为了演示作用,正常环境不会有==========】function callListFn(arr, ismac) {let curr = arr.shift();curr();//再检测下是否有微任务//这里其实这样写不啊合适,只是暂时配合模拟效果if (ismac) {//微任务while (microTask.length) {callListFn(microTask);}}}//微任务while (microTask.length) {callListFn(microTask);}//宏任务while (macroTask.length) {callListFn(macroTask, true);}//模拟事件循环,定时轮询timer = setTimeout(() => {eventLoop();}, 1000)};//事件循环//开启事件循环eventLoop();
setTimeoutx(()=>{console.log("timer1")//模拟Promise.resolve(1).then 这个apimicpush(()=>{console.log("promise1")})console.log("timer 1normal")})setTimeoutx(()=>{console.log("timer2")})console.log("primary")console.warn("macroTask",macroTask,'microTask',microTask)
你会发现浏览器console.log打印的内容和我们第一段代码一模一样
setTimeout,Promise.resolve(1).then他们都是往底层的任务队列里面添加个函数元素而已,并非任务本身,函数类型的参数才是要被执行的任务,只是执行的权限交给了事件轮询。而事件轮询是定期的遍历执行微任务队列和宏任务队列里面的元素。只是微任务的执行优先于宏任务。
注意序号❕
//1setTimeout(()=>{//4console.log("timer1")// 5Promise.resolve(1).then(()=>{//8 console.log("promise1")})//6Promise.resolve(1).then(()=>{//9 console.log("promise1")})//7console.log("timer 1normal")})//2.setTimeout(()=>{//10 console.log("timer2")})// 3console.log("primary")
针对上面不同步骤的微任务队列和 任务队列
//1
macroTask = [fn1];//宏任务
microTask = [];//微任务
//2
macroTask = [fn1,fn2];//宏任务
microTask = [];//微任务
//3
macroTask = [fn1,fn2];//宏任务
microTask = [];//微任务
执行【打印"primary”】
【开始事件轮询1】
//4
执行【打印"timer1”】
macroTask = [fn2];//宏任务,正在执行fn1宏任务,所以要把他移除处队列
microTask = [];//微任务
//5
执行【打印"timer1”】—已经执行了,
macroTask = [fn2];//宏任务,正在执行fn1宏任务,所以要把他移除处队列
microTask = [fn3];//微任务,Promise.resolve(1).then 给微任务队列塞入个元素
//6
执行【打印"timer1”】—已经执行了,
macroTask = [fn2];//宏任务,正在执行fn1宏任务,所以要把他移除处队列
microTask = [fn3,fn4];//微任务,Promise.resolve(1).then 给微任务队列塞入个元素
//7
执行【打印"timer 1normal”】
macroTask = [fn2];//宏任务,没有执行下一个事件轮训所以【本轮事件轮训】宏任务还有一个元素
microTask = [fn3,fn4];//微任务,因为还没有执行下一个事件轮训所以【本轮事件轮训】微任务还有2个元素
//开启第二轮事件轮询,8,9,10,微任务【8,9】优先
最终
microTask = [];//微任务
macroTask = [];//宏任务
以上的代码可以在线测试