异步执行顺序
任务队列
JavaScript经过任务队列管理全部异步任务,而任务队列还能够细分为MacroTask Queue和MicoTask Queue两类。html
MacroTask Queue
MacroTask Queue(宏任务队列)主要包括setTimeout, setInterval, setImmediate, requestAnimationFrame, UI rendeing, NodeJS中的`I/O等。promise
MicroTask Queue
MicroTask Queue(微任务队列)主要包括两类:bash
1.独立回调microTask:如Promise,其成功/失败回调函数相互独立;异步
2.复合回调microTask:如 Object.observe, MutationObserver 和NodeJs中的 process.nextTick ,不一样状态回调在同一函数体;async
MacroTask和MicroTask
JavaScript将异步任务分为MacroTask和MicroTask,那么它们区别何在呢?函数
- 依次执行同步代码直至执行完毕;
- 检查MacroTask队列,如有触发的异步任务,则取第一个并调用其事件处理函数,而后跳至第三步,若没有需处理的异步任务,则直接跳至第三步;
- 检查MicroTask队列,而后执行全部已触发的异步任务,依次执行事件处理函数,直至执行完毕,而后跳至第二步,若没有需处理的异步任务中,则直接返回第二步,依次执行后续步骤;
- 最后返回第二步,继续检查MacroTask队列,依次执行后续步骤;
- 如此往复,若全部异步任务处理完成,则结束;
promise、setTimeout、async的前后执行顺序
准则:
1.先执行同步代码,遇到异步代码就先加入队列,而后按入队顺序执行异步代码,最后执行setTimeout队列的代码
2.setTimeout的任务队列优先级低于promise队列,setTimeout的队列与promise不是一个队列
3.setTimeout有默认4ms的延迟,因此不会当即执行,而是会进入宏队列
4.await会让出当前线程,将后面的代码加到任务队列中,而后继续执行test()函数后面的同步代码
复制代码
async function async1() {
console.log("async1 start"); //(2)
await async2();
console.log("async1 end"); //(7)
}
async function async2() {
console.log( 'async2'); //(3)
}
console.log("script start"); //(1)
setTimeout(function () {
console.log("settimeout"); //(8)
},0);
async1();
new Promise(function (resolve) {
console.log("promise1"); //(4)
resolve();
}).then(function () {
console.log("promise2"); //(6)
});
console.log('script end');//(5)
复制代码
解析:
先按顺序执行同步代码 从‘script start‘开始,
执行到setTimeout函数时,将其回调函数加入队列(此队列与promise队列不是同一个队列,执行的优先级低于promise)。
而后调用async1()方法,await async2();//执行这一句后,输出async2后,await会让出当前线程,将后面的代码加到任务队列中,而后继续执行test()函数后面的同步代码
继续执行建立promise对象里面的代码属于同步代码,promise的异步性体如今then与catch处,因此promise1被输出,而后将then函数的代码加入队列,继续执行同步代码,输出script end。至此同步代码执行完毕。
开始从队列中调取任务执行,因为刚刚提到过,setTimeout的任务队列优先级低于promise队列,因此首先执行promise队列的第一个任务,由于在async函数中有await表达式,会使async函数暂停执行,等待表达式中的 Promise 解析完成后继续执行 async 函数并返回解决结果。
因此先执行then方法的部分,输出promise2,而后执行async1中await后面的代码,输出async1 end。。最后promise队列中任务执行完毕,再执行setTimeout的任务队列,输出settimeout。
setTimeout(fn,0)的含义是指某个任务在主线程最先可得的空闲时间执行。它在“任务队列”的尾部添加一个事件,所以要等到同步任务和“任务队列”现有的时间处理完才会获得执行。
复制代码
仅用于我的整理,参考:post