请分析以下函数输出顺序
async function asy1() {
console.log(1);
await asy2();
console.log(2);
}
async function asy2() {
await setTimeout(() => {
Promise.resolve().then(() => console.log(3));
}, 0);
console.log(4);
}
asy3 = async () => {
Promise.resolve(6).then(() => console.log(6));
};
asy1();
console.log(7);
asy3();
代码看着比较复杂,我们可以试着简化下代码,先把 asy2 简化下,把 async 改写成普通的 Promise 链式调用,看起来更清晰, 首先 setTimeout 会返回一个定时器 id,是个 number 类型,那其实就等价于 await 1 根据 js 标准文档 developer.mozilla.org/zh-CN/docs/…
async function foo() {
await 1;
}
等价于
function foo() {
return Promise.resolve(1).then(() => undefined);
}
因此 asy2 可以改写成
function asy2() {
setTimeout(() => {
Promise.resolve().then(() => console.log(3));
}, 0);
return Promise.resolve(1)
.then(function () {
console.log(4);
});
}
接下来把 asy1 也改写成普通的 Promise 链式调用
function asy1() {
console.log(1);
asy2().then(() => {
console.log(2);
});
}
来看下改写后的完整代码
function asy1() {
console.log(1);
asy2().then(() => {
console.log(2);
});
}
async function asy2() {
setTimeout(() => {
Promise.resolve().then(() => console.log(3));
}, 0);
return Promise.resolve(1)
.then(function () {
console.log(4);
});
}
asy3 = async () => {
Promise.resolve(6).then(() => console.log(6));
};
asy1();
console.log(7);
asy3();
好像看着还是有点复杂,那我们试着把 asy1 和 asy2 合并下,并且去掉函数封装,直接执行,这样看着更加直观,最终代码如下
console.log(1);
setTimeout(() => {
Promise.resolve().then(() => console.log(3));
}, 0);
Promise.resolve(1)
.then(function () {
console.log(4);
})
.then(() => {
console.log(2);
});
console.log(7);
Promise.resolve(6).then(() => console.log(6));
根据 js 事件循环机制,首先将同步代码放到执行栈执行,也就是先执行
console.log(1);
console.log(7);
输出顺序为 1 7
同时将 Promise.resolve().then(() => console.log(3));
放到宏任务队列,接着往下看
运行到 Promise.resolve(1) ,将其加入微任务队列,我们注意到后面同时写了 2 个 then 回调,但是此时 js 引擎只会等
Promise.resolve(1) 执行完成后才会将 then 中的回调加入到微任务队列,举个例子
以下代码其运行顺序的伪代码为 1 2 3 4
Promise.resolve()
.then(() => console.log(1))
.then(() => console.log(3))
Promise.resolve()
.then(() => console.log(2))
.then(() => console.log(4))
所以对于
Promise.resolve(1)
.then(function () {
console.log(4);
})
.then(() => {
console.log(2);
});
console.log(7);
Promise.resolve(6).then(() => console.log(6));
可以很容易知道顺序为 7 4 6 2,根据js引擎会将当前微任务队列全部清空,再去执行一个宏任务的原则,我们可以知道最后输出顺序为 1 7 4 6 2 3