Skip to main content

async/await 原理与异步工具

async/await 的本质

async/awaitGenerator + 自动执行器(co) 的语法糖:

  • async function ≈ 返回 Promise 的 Generator 函数
  • awaityield,暂停函数执行,等待 Promise 完成后把结果回填

用 Generator + co 模拟 async/await

// 自动执行器:不断驱动 generator,遇到 Promise 就等它完成再继续
function co(genFn) {
return new Promise((resolve, reject) => {
const gen = genFn();

function step(nextFn) {
let next;
try {
next = nextFn(); // 可能是 gen.next(v) 或 gen.throw(e)
} catch (e) {
return reject(e); // generator 内部抛错
}

const { value, done } = next;
if (done) return resolve(value); // 执行完毕

// 把 yield 出来的值统一包成 Promise
Promise.resolve(value).then(
(v) => step(() => gen.next(v)), // 成功:把结果回填给 yield
(e) => step(() => gen.throw(e)) // 失败:把错误抛回 generator
);
}

step(() => gen.next());
});
}

// 用法:把 async 换成 co,await 换成 yield
co(function* () {
const a = yield Promise.resolve(1);
const b = yield Promise.resolve(a + 1);
return a + b; // 3
}).then(console.log);

sleep(暂停)

const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

async function demo() {
console.log("start");
await sleep(1000);
console.log("1s later");
}

失败重试 retry

function retry(fn, times = 3, delay = 1000) {
return new Promise((resolve, reject) => {
const attempt = (remaining) => {
Promise.resolve(fn())
.then(resolve)
.catch((err) => {
if (remaining <= 0) return reject(err);
setTimeout(() => attempt(remaining - 1), delay);
});
};
attempt(times);
});
}

常见追问

  • await 后面跟非 Promise 会怎样? 会被 Promise.resolve() 包裹,下一行进入微任务队列。
  • async 函数一定异步吗? 函数体内第一个 await 之前的代码是同步执行的,遇到 await 才让出。
  • 如何并行多个 await?Promise.all,避免「串行 await」造成的等待累加。

参考