跳到主要内容

异步执行顺序

finally 与 then 的注册顺序如何影响输出?​

Promise.resolve("1")
.then((res) => console.log(res))
.finally(() => console.log("finally"));

Promise.resolve("2")
.finally(() => {
console.log("finally2");
return "我是 finally2 返回的值"; // finally 的返回值被忽略
})
.then((res) => console.log("finally2 后面的 then", res));

// 1
// finally2
// finally
// finally2 后面的 then 2
  • 规律: 每个 then/finally 注册为一个微任务, 按注册顺序入队; finally 不改变链上的值;

async、await、setTimeout 与 Promise 交错时如何阅读?​

const async1 = async () => {
console.log("async1 start");
await async2();
console.log("async1 end");
};
const async2 = () => console.log("async2");

console.log("script start");
setTimeout(() => console.log("setTimeout"), 0);
async1();
new Promise((resolve) => {
console.log("promise1");
resolve(1);
console.log("resolve after");
}).then(() => console.log("promise2"));
console.log("script end");

// script start
// async1 start
// async2
// promise1
// resolve after
// script end
// async1 end
// promise2
// setTimeout
  • 步骤:
    1. 同步代码依次执行: script start、async1 start、async2, 遇到 await 让出, 把恢复任务入微任务队列;
    2. 进入 Promise 构造器同步执行 promise1、resolve(1)、resolve after, then 回调入微任务队列;
    3. 打印 script end, 同步代码结束;
    4. 清空微任务队列: 先恢复 async1 打印 async1 end, 再执行 promise2;
    5. 宏任务队列中的 setTimeout 最后执行;

await 链与宏任务交错时如何阅读?​

const sleep = async () =>
new Promise((resolve) => {
console.log("sleep before");
setTimeout(resolve, 1000);
}).then(() => console.log("sleep after"));

const fn = async () => {
console.log("fn");
await sleep();
return null;
};
async function foo() {
console.log(2);
console.log(await fn());
console.log(4);
}

console.log(1);
foo().then(() => console.log("end"));
console.log(3);

// 1
// (foo) 2
// (fn) fn
// (sleep) sleep before
// 3
// —— 1s 后恢复 ——
// sleep after
// null
// 4
// end
  • 阅读方法: 先执行到最内层 await 的同步部分, 再逐层把恢复任务推入微任务队列; 计时器到时后从宏任务恢复整条 await 链;