异步—手写 async_await
前言
如果让你手写 async 函数的实现,你是不是会觉得很复杂?这篇文章带你用 20 行搞定它的核心。
经常有人说 async 函数是 generator 函数的语法糖,那么到底是怎么样一个糖呢?让我们来一层层的剥开它的糖衣。
有的同学想说,既然用了 generator 函数何必还要实现 async 呢?
这篇文章的目的就是带大家理解清楚 async 和 generator 之间到底是如何相互协作,管理异步的。
示例
const getData = () =>
new Promise(resolve => setTimeout(() => resolve('data'), 1000))
async function test() {
const data = await getData()
console.log('data: ', data)
const data2 = await getData()
console.log('data2: ', data2)
return 'success'
}
// 这样的一个函数 应该再1秒后打印data 再过一秒打印data2 最后打印success
test().then(res => console.log(res))
思路
对于这个简单的案例来说,如果我们把它用 generator 函数表达,会是怎么样的呢?
function* testG() {
// await被编译成了yield
const data = yield getData()
console.log('data: ', data)
const data2 = yield getData()
console.log('data2: ', data2)
return 'success'
}
我们知道,generator 函数是不会自动执行的,每一次调用它的 next 方法,会停留在下一个 yield 的位置。
利用这个特性,我们只要编写一个自动执行的函数,就可以让这个 generator 函数完全实现 async 函数的功能。
const getData = () =>
new Promise(resolve => setTimeout(() => resolve('data'), 1000))
var test = asyncToGenerator(function* testG() {
const data = yield getData()
console.log('data', data)
const data2 = yield getData()
console.log('data2', data2)
return 'success'
})
test().then(res => console.log(res))
那么大体上的思路已经确定了,
asyncToGenerator
接受一个generator
函数,返回一个promise
,
关键就在于,里面用yield
来划分的异步流程,应该如何自动执行。
如果是手动执行
在编写这个函数之前,我们先模拟手动去调用这个generator
函数去一步步的把流程走完,有助于后面的思考。
function* testG() {
// await被编译成了yield
const data = yield getData()
console.log('data: ', data);
const data2 = yield getData()
console.log('data2: ', data2);
return 'success'
}
← JS 基础 JS 异步编程:种类和原理 →