Open
Description
概念
ES2017 引入的 async
, await
实际上是 Generator 函数的语法糖,使异步操作的写法更加方便。
(既然是语法糖,那我们就可以尝试用 Generator 自己去手写一个 async, await 了 😆 )
跟 Generator 函数比较,可以发现,语法上,就是把 *
号换成 async
, yield
关键字换成 await
而已。但是,肯定不只是替换关键字这么简单,不然为何不用 Generator 。
对 Generator 的改进
- 内置执行器,不用像 Generator 函数返回迭代器那种模式那样,手动去执行
next
- 更好的语义
- async 函数的返回值是 Promise
实现一个 async
假设有以下代码:
function getAsyncValue () {
return new Promise((resolve, reject) => {
setTimeout(resolve, 10, 123)
})
}
async function asyncFunction (p) {
console.log('param: ', p)
const value = await getAsyncValue()
return value
}
asyncFunction(666).then((result) => {
console.log(result)
})
// param: 666
// 123
如果只依赖 Generator
与 yield
语法,不使用 async
, await
,但要实现同样效果的话,首先把 await
替换成 yield
,然后实现 async
包装:
const _async = (generator) => {
return function (...args) {
// async 函数返回一个 Promise
return new Promise((resolve, reject) => {
// Promise 内部会自动将 Generator 函数返回的迭代器执行到最后
const it = generator(...args)
const step = (nextFunction) => {
let next
try {
next = nextFunction()
} catch (e) {
reject(e)
}
if (next.done) {
return resolve(next.value)
}
// 其中, next 的执行时机就是 yield 后面的 Promise 状态改变的时候
// next 的参数就是上一个 yield 的值
Promise.resolve(next.value).then((value) => {
return step(() => it.next(value))
}, (reason) => {
return step(() => it.throw(reason))
})
}
step(() => it.next())
})
}
}
最后就可以改写成非语法糖的 Generator
语法形式:
function getAsyncValue () {
return new Promise((resolve, reject) => {
setTimeout(resolve, 10, 123)
})
}
const asyncFunction = _async(function* (p) {
console.log('param: ', p)
const value = yield getAsyncValue()
return value
})
asyncFunction(666).then((result) => {
console.log(result)
})
// param: 666
// 123