手写 async 与 await
约 444 字大约 1 分钟
2026-02-26
async/await` 的目标是把“异步回调链”改写成“看起来像同步”的流程代码。
基础规则
| 规则 | 说明 |
|---|---|
async 函数返回值 | 一定是 Promise |
await 后面 | 可以是 Promise,也可以是普通值 |
await 行为 | 暂停当前函数,等待结果后继续 |
| 异常处理 | 用 try...catch 捕获异步错误 |
async function getUser() {
return { id: 1, name: 'Tom' }
}
getUser().then((res) => {
console.log(res) // { id: 1, name: 'Tom' }
})常见写法
顺序执行
async function run() {
const a = await Promise.resolve(1)
const b = await Promise.resolve(2)
return a + b
}
run().then(console.log) // 3并发执行
async function run() {
const [user, posts] = await Promise.all([
fetch('/api/user').then((r) => r.json()),
fetch('/api/posts').then((r) => r.json()),
])
return { user, posts }
}错误处理
async function run() {
try {
const data = await fetch('/api/fail').then((r) => r.json())
return data
}
catch (err) {
console.error('request error:', err)
return null
}
}用迭代器/生成器实现一个 async/await
实现思路:
- 用
function*写异步流程(每一步yield一个 Promise)。 - 写一个执行器
spawn,自动调用next()。 - 当
yield出来的 Promise 完成后,把结果再传回生成器。 - 出错时调用
iterator.throw(error),让try...catch生效。
定义执行器
spawnfunction spawn(genFn, ...args) { return new Promise((resolve, reject) => { const iterator = genFn(...args) function step(method, arg) { let result try { result = iterator[method](arg) } catch (error) { reject(error) return } const { value, done } = result if (done) { resolve(value) return } Promise.resolve(value).then( (val) => step('next', val), (err) => step('throw', err), ) } step('next') }) }用生成器描述异步流程
const delay = (ms, value) => new Promise((resolve) => { setTimeout(() => resolve(value), ms) }) function* flow() { const a = yield delay(100, 1) const b = yield delay(100, a + 1) return b + 1 }运行效果
spawn(flow).then(console.log) // 3封装成
asyncToGeneratorfunction asyncToGenerator(genFn) { return function (...args) { return spawn(genFn, ...args) } } const run = asyncToGenerator(function* (name) { const user = yield Promise.resolve({ id: 1, name }) const role = yield Promise.resolve('admin') return { ...user, role } }) run('Tom').then(console.log) // { id: 1, name: 'Tom', role: 'admin' }
