欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

ES的迭代器Iterator和生成器Generator

程序员文章站 2024-02-12 12:44:49
...

一、简介

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);
  };
})();

转载于:https://www.jianshu.com/p/43b3f254f339