Generator – 生成器

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
 

原创文章,作者:我心飞翔,如若转载,请注明出处:https://www.pipipi.net/14825.html

发表评论

登录后才能评论