一、什么是generator函数
(1)generator本身是用来生成迭代器的。在async和await被官方正式引入标准前用来模拟async和await,作为一另种js异步编程解决方案。
generator函数执行过程中可以暂停(使用yield)再继续(调用遍历器对象next方法),暂停的时候将函数执行权交出给其他函数,比如异步操作,等其他函数执行完了以后,执行权会返回回来,此时可以拿到异步操作的结果,继续恢复执行。
//* 可以挨着function或者函数名,但是中间必须有空格
function* myGenerator(){
yield setTimeout(()=>{
console.log('其他函数执行')
},1000);
yield new Promise((resolve)=>{
setTimeout(()=>{resolve('resolved')},1000)
})
return 'value returned'
}
let myIterator = myGenerator()
myIterator.next() //{value: 定时器id, done:false}
myIterator.next() //{value: promise, done:false}
myIterator.next() //{value: 'value returned', done:true}
(2)yield与return对比<br />yield可以暂停函数执行,并将后面表达式的值(**惰性求值**,遇到next方法后才会求值)作为返回对象的value值,可暂停多次<br />return可以返回值,直接终止函数执行<br />(3)next方法<br />next方法的作用是,**推动函数执行**,如果遇到yield,函数交出执行权,<br />next参数为**上一次yield表达式的值**。第一次调用next方法时传的参数是在generator函数中接受不了的,因为第一次调用next方法,遇到yield,函数就暂停运行,yield表达式并没有进行求值计算。
function *gen(){
let a = yield 123 + 567;
console.log(a, 'a')
let b = yield 123 + 678;
console.log(b,'b')
}
let iter = gen();
iter.next() // 函数开始执行,遇到yield暂停
iter.next(2) // =>2 'a' 上一次yield方法表达式为
iter.next(3) // =>3 'b'
// 如果没有传参,yield表达式的值为undefined
二、迭代器和遍历
如果用遍历来执行一些函数,遍历不会中断,只能在每次迭代中增加逻辑,迭代器可以精确控制每一次迭代,可以避免无意义的迭代。
使用场景:中间件的迭代调用,中间件一般会有next方法,只有调用next方法后,才会执行下一个中间件。
路由钩子router.beforeEach,axios拦截器中都有next方法,调用next方法才会进入下一步。
遍历和迭代好比上楼梯,遍历是走过每一层楼,整个过程是连续的,迭代是中间的一个动作,迭代一次,上一层楼。
三、手写generator函数
核心是函数返回一个对象,每次调用迭代器对象的next方法,迭代数组一次
function generator (arr){
let arrLenght = arr.length,
currentIndex = 0;
return {
next(){
return {value: arr[currentIndex++], done: currentIndex >= arrLenght}
}
}
}
let iterator = generator([1,2,3,4,5]);
console.log(iterator)
四、generator与iterator在一系列中间件执行中的引用。
核心思想就是:将函数数组传入生成器生成迭代器,然后先调用init函数,进行第一次迭代,给函数传入next方法(调用迭代器next方法,将迭代结果传入是否迭代判断函数进行递归操作),调用数组里的函数。
;(function(functions){
function *functGenerator(){
for(let item of functions){
//之前把item执行了,导致后面报错
yield item
}
}
let iterator = functGenerator();
//这个函数是用来接收每次迭代返回的对象,根据done来判断是否进行迭代,并提供下一次迭代功能
function checkNextDo(iteratorResult){
//数组迭代最后到最有一个元素时,done还是为false,之后迭代返回对象的done才为true,
//所以这里先调用函数还是先判断是否迭代结束都不影响
if(iteratorResult.done){
return
}else{
//没有迭代完成,接续迭代,此时需要传一个参数函数,提供下一次迭代功能,然后再判断
//调用当前迭代到的函数
iteratorResult.value(function(){
checkNextDo(iterator.next())
})
}
}
function init(){
checkNextDo(iterator.next())
}
init()
})(
[
function test1(next){
console.log('test1')
next()
},
function test2(next){
console.log('test3')
next()
},
function test3(next){
console.log('test3')
next()
},
function test4(next){
console.log('test4')
},
])
// test1
// test2
// test3