迭代器与生成器

在JavaScript中一个迭代器是一个对象,该对象有一个next()方法,每次调用都返回一个结果对象({done,value}),done表示序列中的值已经消费完毕,value表示迭代值

举个栗子

function makeRangeIterator(start = 0, end = Infinity, step = 1) {
    let nextIndex = start;
    let iterationCount = 0;

    const rangeIterator = {
       next: function() {
           let result;
           if (nextIndex <= end) {
               result = { value: nextIndex, done: false }
               nextIndex += step;
               iterationCount++;
               return result;
           }
           return { value: iterationCount, done: true }
       }
    };
    return rangeIterator;
}
let it = makeRangeIterator(1, 10, 2);

let result = it.next();
while (!result.done) {
 console.log(result.value); // 1 3 5 7 9
 result = it.next();
}

console.log("Iterated over sequence of size: ", result.value); // 5

Iterables

ES6 开始,从一个 iterable 中提取迭代器的方法是:iterable 必须支持一个函数,其名称是专门的 ES6 符号值 Symbol.iterator。调用这个函数时,它会返回一个迭代器。

如果对象想要可遍历需要实现Iterator 接口,下面是定义一个可迭代对象:

[ .. ] 语法被称为计算属性名,Symbol.iterator 是 ES6 预定义的特殊Symbol 值之一

for..of 循环期望 obj 是 iterable,于是它寻找并调用它的 Symbol.iterator 函数。

生成器

生成器是一种返回迭代器的函数,一般一个函数一旦开始执行,就会运行到结束,期间不会有其他代码能够打断它并插入其间,生成器并不符合这种运行到结束的特性。

首先传入6作为参数 x 然后执行 it.next(),这会启动 *foo(..)

foo(..) 内部,开始执行语句 var y = x ..,但随后就遇到了一个 yield 表达式。它 就会在这一点上暂停 foo(..),并在本质上要求调用代码为 yield 表达式提供一个结果值。接下来,调用 it.next( 7 ),这一句把值 7 传回作为被暂停的 yield 表达式的结果。所以,这时赋值语句实际上就是 var y = 6 * 7。现在,return y 返回值 42 作为调用 it.next( 7 ) 的结果。

  • 第一个 next(..) 总是启动一个生成器,并运行到第一个 yield 处

  • 第二个 next(..) 调用完成第一个被暂停的 yield 表达式,也就是设置上一个yield表达式的结果值

  • 第三个 next(..) 设置第二个yield表达式的值,以此类推..

如果把yield和return一起使用的话, 那么return的值也会作为最后的返回值, 如果return语句后面还有yield, 那么这些yield不生效:

生成器+Promise

yield 出来一个 Promise,侦听这个 promise 的决议(完成或拒绝),通过这个 Promise 来控制生成器的迭代器,

支持 Promise 的 Generator Runner

promise并发请求

ES6 之前的生成器

思考下面代码如何转换成ES5

手动转换,根据生成器的定义大概轮廓:

生成器的几种状态:1.初始状态触发request请求 2.request请求成功后的状态 3.是 request(..) 失败的状态。

ES7:async 与 await

Last updated

Was this helpful?