async函数是generator函数的语法糖
generator函数的作用可以使函数分段执行
function* generator(){
yield 1
yield 2
yield 3
}
let gen = generator()
gen.next() //{ value: '1', done: false }
gen.next() //{ value: '2', done: false }
gen.next() //{ value: '3', done: false }
gen.next() //{ value: undefined, done: true }因为generator函数读到yield就会停止,而next的控制权又是在我们手里,所有有没有可能我们yeild后面执行一段异步操作,在异步执行完调用next,让generator函数继续执行下去呢?
首先我们先要实现一个基础的generator自执行的执行器
function next(){
let res = gen.next()
if(!res.done){
next()
}
}
next(gen)然而,我们的目的是要实现yield停止的是时候执行异步函数,如下
function* generator(){
yield readFile
yield readFile
yield readFile
}要实现异步函数的generator执行器,需要我们把next暴露给异步函数,在异步执行完后调用
function next(){
let res = gen.next()
if(!res.done){
if(typeof res.value === 'function'){
res.value(next)
}
}
}这样就可以实现generator中异步函数的自执行了,但是这种异步函数是不可以传参的,于是我们还需要一个包装器
function thunk(asyncFn){
return function(...args){
return function(next){
asyncFn(args,next)
}
}
}
let thunkAsync = thunk(async)
function* generator(){
yield thunkAsync("file1")
yield thunkAsync("file2")
yield thunkAsync("file3")
}完整代码如下:
function thunk(fn){
return function(...args){
return function(next){
fn(...args,next)
}
}
}
function async(){
let args = Array.prototype.slice.call(arguments)
let next = args[args.length-1]
args.pop()
setTimeout(()=>{
console.log("参数:",...args)
next()
},1000)
}
let thunkAsync = thunk(async)
function* generator(){
yield thunkAsync("file1")
yield thunkAsync("file2")
yield thunkAsync("file3")
}
let gen = generator()
function next(){
let res = gen.next()
if(!res.done){
if(typeof res.value === 'function'){
res.value(next)
}
}
}
next(gen)这还不够简便,我们开发中总是手动执行一下next会很烦,有没有可能让next方法也自动实现呢。这就需要借助promise函数,在promise中异步执行完毕执行resolve的时候隐式的调用next
promise函数的generator执行器
function next(){
let res = gen.next()
if(!res.done){
if(res.value instanceof Promise){
res.value.then(function(val){
next()
return val
})
}
}
}完整代码如下:
function promiseAsync(args){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
console.log(args)
resolve()
},1000)
})
}
function* generator(){
yield promiseAsync("file1")
yield promiseAsync("file2")
yield promiseAsync("file3")
}
let gen = generator()
function next(){
let res = gen.next()
if(!res.done){
if(res.value instanceof Promise){
res.value.then(function(val){
next()
return val
})
}
}
}
next(gen)总结:其实异步的实现就是暴露next给外部,在异步结束的时候调用,如果是promise函数,可以在resolve执行时隐式调用。在上篇文章中介绍的异步队列的执行由很多共同点,感兴趣的可以学习交流下juejin.cn/post/684490…