ES的迭代器Iterator和生成器Generator

一、简介

1.1 集合对象迭代器

迭代器是一种常用的设计模式,人们常用它来遍历集合对象。在ES6中,有Array、Map和Set三种常用的集合对象,他们都内建了三种迭代器:

  • entries() 返回键值对迭代器
  • keys() 返回键名迭代器
  • values() 返回集合值迭代器
    所有的迭代器对象都有一个next()方法,每次调用都会返回一个{value: value, done: Boolen}对象,当没有可返回数据时done的值为true。for-of循环就是每次执行的时候都会去调用迭代器的next(),直至done属性的值为true。相比于for循环,for-of循环可以避开集合的索引跟踪只需关注集合中需要处理的内容。
for(let entry of map.entries()){}
for(let key of array.keys()){}
for(let value of set.values()){}

1.2 默认的迭代器

Array、Map和Set虽然都有三个内建迭代器,但是他们默认的迭代器是不同的,比如Map的默认迭代器是entries,Set的默认迭代器是values。我们可以通过Symbol.iterator来获取可迭代对象的默认迭代器。例如:

let map = new Map();
let iterator = map[Symbol.iterator]();

此外,我们也可通过Symbol.iterator创建一个可迭代对象:

let collection = {
  items: [],
  *[Symbol.iterator]() {
    for (let item of items) {
      yield item;
    } 
  }
};

collection.items.push(1);
collection.items.push(2);
collection.items.push(3);

for (let x of collection) {
  console.log(x);
} 

二、原理浅析

先看一下高级迭代器的代码。

function *createIterator() {
    console.log('begin');
    let a = yield 1;
    console.log('a', a);
    let b = yield a + 2;
    console.log('b', b);
    yield b + 3;
    console.log('finish');
}
let iterator = createIterator();
iterator.next(0); // return {value: 1, done: false}
// begin
iterator.next(2); // return {value: 4, done: false}
// a 2
iterator.next(4);// return {value: 6, done: false}
// b 4
iterator.next(6);// return {value: undefined, done: true}
// finish

通过上面高级迭代器的代码和输出,我们可以看出迭代器的运行原理。生成器Generator的代码根据yield关键字被拆分成了多个函数,类似于split('yield')的效果。在运行了iterator.next(0);之后createIterator执行了console.log('begin'); yield 1;。至于let a = yield 1;,相当于return 1let a = next(),所以a的值是iterator.next(2);的参数2。

三、async/await

ES6发布了Generator和Promise两种新特性,不久之后async/await语法被提上议程并在ES7中如约而至。其初衷是用async标记的函数用来代替生成器,用await代替yield来调用函数。然而,async/await却是对Promise和Generator的封装,async/await用Babel转换成ES6的之后是Promise和Generator。不仅如此,浏览器也会像Babel一样去转换async/await。

/**
   * Bable转换func函数
   *
   * async function func() {
   *    await promise();
   *    console.log('finish...');
   *  }
   */
function _asyncToGenerator(fn) {
  return function () {
    var gen = fn.apply(this, arguments);
    return new Promise(function (resolve, reject) {
      function step(key, arg) {
        try {
          var info = gen[key](arg);
          var value = info.value;
        } catch (error) {
          reject(error);
          return;
        }
        if (info.done) {
          resolve(value);
        } else {
          return Promise.resolve(value).then(function (value) {
            step("next", value);
          }, function (err) {
            step("throw", err);
          });
        }
      }

      return step("next");
    });
  };
}

let promise = new Promise(resolve => resolve(1));

let func = (() => {
  let _ref = _asyncToGenerator(function*() {
    yield promise;
    console.log('finish...');
  });

  return function func() {
    return _ref.apply(this, arguments);
  };
})();

你可能感兴趣的:(ES的迭代器Iterator和生成器Generator)