1、调用生成器函数
生成器函数几乎是一个完全崭新的函数类型,他和标准的普通函数完全不同。
生成器函数能生成一组值的序列,但每个值的生成是基于每次请求
,并不同于标准函数那样立刻生成。
//定义一个生成器函数
function* WeaponGenerator(){
yield "Katana";
yield "Wakizashi";
yield "Kusarigama";
}
//调用生成器得到一个迭代器
const weaponsIterator = WeaponGenerator();
//手动依次调用.next方法
//每次调用迭代器的next方法向生成器请求一个新值
weaponsIterator.next();//{ value: 'Katana', done: false }
weaponsIterator.next();//{ value: 'Wakizashi', done: false }
weaponsIterator.next();//{ value: 'Kusarigama', done: false }
weaponsIterator.next();//{ value: undefined, done: true }
//使用for-of循环
for (let item of WeaponGenerator()) {
console.log(item);//Katana、Wakizashi、Kusarigama
}
2、与生成器交互( 传参 )
function* WeaponGenerator(action){
const imposter = yield action;//imposter为下次调用next传递的参
yield imposter + " - " + action;
}
const weaponsIterator = WeaponGenerator("Sk");
weaponsIterator.next().value;//"Sk"
//第二次调用next中传递的参数,作为内部上一次调用yield的返回值
weaponsIterator.next("Hn").value;//"Hn - Sk"
3、抛出异常
每个迭代器除了有一个next方法,还有一个throw方法
function* WeaponGenerator(){
try{
yield "Hattori";
}
catch(e){
return e == "catch this";
}
}
const ninjaIterator = WeaponGenerator();
ninjaIterator.next()//{value: "Hattori", done: false}
ninjaIterator.throw("catch this")//{value: true, done: true}
4、内部构成( 执行原理 )
挂起开始: 创建了一个生成器后,它最先以这种状态开始。其中的任何代码都未执行
执行: 生成器中代码的执行状态。执行要么是刚开始,要么是从上次挂起的时候继续的。当生成器对应的迭代器调用了next方法,并且当前存在可执行的代码时,生成器都会转移到这个状态。
挂起让渡: 当生成器在执行的过程中遇到了一个yield表达式,它会创建一个包含着返回值的新新对象,随后再挂起执行。生成器在这个状态暂停并等待继续执行。
完成: 在生成器执行期间,如果代码执行到return语句或者全局代码执行完毕,生成器就进入该状态
生成器函数
function* WeaponGenerator(){
yield "Hattori";
yield "Yoshi";
}
代码执行过程
//1、创建生成器,处于挂起状态
const ninjaIterator = WeaponGenerator();
//2、激活生成器,从挂起状态转为执行状态。执行到 yield "Hattori" 语句终止
//进而转为挂起状态,返回新对象 {value: "Hattori", done: false}
const result1 = ninjaIterator.next();
//3、重新激活生成器,从挂起状态转为执行状态。执行到 yield "Yoshi" 语句终止
//进而转为挂起状态,返回新对象 {value: "Yoshi", done: false}
const result2 = ninjaIterator.next();
//4、重新激活生成器,从挂起状态转为执行状态。
//没有代码可执行,转为完成状态,返回新对象{value: false, done: true}
const result3 = ninjaIterator.next();
通过执行上下文跟踪生成器函数
-
1、ninjaIterator调用之前:执行栈指向 –> 全局执行上下文
- ninjaIterator:函数
- result1:undefined
- result2:undefined
- result3:undefined
-
2、调用ninjaIterator函数:执行栈指向 –> WeaponGenerator生成器
- 创建新的ninjaIterator对象,指向当前生成器上下文
- 创建一个新的栈元素入栈( WeaponGenerator )
- 此时函数不会执行任何代码,而是返回一个新的迭代器;程序执行完后WeaponGenerator被弹出,但是没有被销毁(由于ninjaIterator的引用)
- WeaponGenerator执行上下文被暂时挂起
- 执行栈指向再次指向全局执行上下文
-
3、调用ninjaIterator.next()方法:执行栈指向 –> WeaponGenerator生成器
- 重新激活对应的上下文,将WeaponGenerator压入到栈中
- 执行完后,再次将WeaponGenerator执行上下文挂起
- 执行栈指向再次指向全局执行上下文
-
4、调用ninjaIterator.next()方法:重复上步操作
-
5、执行完成,结束状态
5、迭代
6、一波源码分析
function createIterator(items) {
var i = 0
return {
next: function () {
var done = (i >= items.length)
var value = !done ? items[i++] : undefined
return {
done: done,
value: value
}
}
[Symbol.iterator]: function () {
return this
}
}
}
var iterator = createIterator([1, 2, 3])
...iterator // 1, 2, 3