深入理解ES6-8.迭代器和生成器(3)

36 阅读2分钟

给迭代器传递参数

迭代器向外传值:

  1. 在生成器内部使用 yield 语句返回值。
  2. 给迭代器的 next() 传递参数,则这个参数会替代生成器中一条 yield 语句的返回值
function *createIterator() {
    let first = yield 1;
    let second = yield first + 2;
    yield second + 3;
}

let iterator = createIterator();
iterator.next();    //"{ value: 1, done: false}"
iterator.next(4);   //"{ value: 6, done: false }"
iterator.next(5);   //"{ value: 8, done: false}"
iterator.next();    //"{ value: undefined, done: true}"

注意点

  1. 第一次调用 next() 方法时传参是无效的,因为 next() 方法的参数是替代上一次 yield 语句的返回值。
  2. 每次执行 next() 方法时,执行完赋值右边的 yield 之后就会暂停,直到下一次 next() 才会执行前一个 yield 语句的赋值。 image.png

在迭代器中抛出错误

迭代器不仅提供了 next() 方法传参,还提供了 throw() 方法抛出错误。通过 throw() 方法,当迭代器恢复执行时可令其抛出一个错误,然后中断后续代码的执行。

iterator.throw(new Error('Boom'))

可以在代码块内部使用 try-catch 捕获这些错误,使得就算出现错误,也可以继续向下执行。

在迭代器内,如果使用了 yield 语句,可以通过 next()throw() 控制执行过程,也可以使用 return 语句返回一些不一样的内容。

生成器返回语句

在生成器中,return 表示操作完成,其后的语句都不会执行,所以会将 done 属性置为 true,将 value 属性置为 return 的返回值,没有返回值为 undefined

function *createIterator() {
    yield 1;
    return 42;
    yield 2;
}

let iterator = createIterator();
iterator.next();    //"{ value: 1, done: false}"
iterator.next();    //"{ value: 42, done: true}"
iterator.next();    //"{ value: undefined, done: true}"

通过 return 指定的返回值,只会在返回对象中出现一次,在后续调用中,value 会被重置为 undefined

委托生成器

合并两个生成器

合并两个生成器,只需要新建一个生成器,然后将这两个生成器的 name 放在其中的 yield 后面即可,中间需要加上星号。

function *createCombinediterator() {
    yield *createiterator1();
    yield *createiterator2();
    yield 'hello';
    yield *'hello';
}

这里的 createCombinediterator 生成器先后委托createiterator1createiterator2 两个生成器。

这里值得注意的是,yield 'hello'在调用 next() 时会返回 hello 这个字符串。而 yield *'hello'会调用 hello 这个字符串的默认迭代器,也就是一个字符一个字符的返回。

异步任务执行

我们希望每隔 1000ms 输出1、2、3,但又不想多层回调函数嵌套使用,就可以使用生成器来简化。

function task(gen){
    let iterator = gen();
    result = iterator.next();
    function step(){
        setTimeout(() => {
            if(!result.done){
                result = iterator.next();
                step();
            }
        }, 1000);
    }
    step();
}
function* gen(){
    console.log(1);
    yield;
    console.log(2);
    yield;
    console.log(3);
}
function task3() {
    console.log(6);
}
task(gen);