关于异步执行顺序的理解
一前言
相信很多人都被异步执行,搞得晕晕的,异步任务不按常理出牌,难以理解。我以自己的理解尝试给大家解释一下。说的不对,多多指教。
二 基础知识
首先js执行过程
所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。
主线程之外,还存在"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。
一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。
微任务先于宏任务执行
主线程不断重复上面的第三步
我们知道异步任务分为微任务,和宏任务。不知道也没关系,
宏任务: script(整体代码), setTimeout, setInterval, setImmediate, I/O, UI rendering
微任务: process.nextTick(Nodejs), Promises, Object.observe, MutationObserver;
理论就是如此了
(注意:如果你不知道队列的特性,很可能就搞不懂接下来的发生的问题)
话不多说,直接来题
setTimeout(function () {
console.log('8')
}, 0)
async function async1() {
console.log('1')
const data = await async2()
console.log('6')
return data
}
async function async2() {
return new Promise(resolve => {
console.log('2')
resolve('async2的结果')
}).then(data => {
console.log('4')
return data
})
}
async1().then(data => {
console.log('7')
console.log(data)
})
new Promise(function (resolve) {
console.log('3')
resolve()
}).then(function () {
console.log('5')
})
是不是直接懵了!
别急 我们一步一步分析
首先setineout是宏任务,加入宏任务队列向下执行定义,又是定义不管
然后执行到async1(),
console.log('1')同步代码直接打印
执行async2
promise内的代码立即执行。console.log('2')此时将.then后面代码console.log('4')加入微任务队列
然后返回async1
知识点;await后面的代码可以看成一个微任务队列,并且会阻塞代码
此时跳出了async1
到了new promise。
promise内的代码立即执行console.log('3')
然后将.then()后面的 console.log('5') 加入微任务队列,
此时微任务中有console.log('4')console.log('5')根据队列先进先出的顺序输出
然后再跳回到await async2()将后面的 console.log('6') 加入微任务
此时跳到async1().then(data => {
console.log('7')
console.log(data)
})将.then后面的 console.log('7')console.log(data)加入微任务。此时又执行完了,输出微任务队列的任务。最后执行宏任务的定时器任务
所以执行顺序是
**1 2 3 4 5 6 7 async的结果 8**
学废了吗
再来一道试试
async function async1() {
console.log('async1 start')
await async2()
console.log('async1 end')1
}
function async2() { // 去掉了 async 关键字
console.log('async2');
}
console.log('script start')
setTimeout(function () {
console.log('setTimeout')
}, 0)
async1();
new Promise(function (resolve) {
console.log('promise1')
resolve();
}).then(function () {
console.log('promise2')
})
console.log('script end')
首先两个函数定义不管
同步代码console.log('script start') 直接输出
定时器宏任务放入宏任务队列
执行async1
直接输出console.log('async1 start')
执行async2直接输出console.log('async2');
await后面console.log('async1 end')加入微任务队列。
new promise体内立即执行console.log('promise1')
.then后面的 console.log('promise2')加入微任务队列
然后直接输出console.log('script end')。
现在要执行微任务队列的
顺序输出console.log('async1 end')console.log('promise2')
微任务执行完毕
执行宏任务,将 console.log('setTimeout') 输出,执行完毕
所以顺序是
script start
async1 start
async2
promise1
script end
async1 end
promise2
setTimeout
如果搞不清楚就回上去看理论知识。所有的顺序都基于理论,然后多做几道题,在温故知新。
(注意:不同浏览器,或者node环境里顺序会造成细微差别实属正常)
希望这篇文章对或多或少你有帮助
做个测试吧
前端工程师 面试题
最后 瑞斯掰~