async await的原理是什么?第一次听到这个问题是有点懵逼,这还有原理吗?但得知async await 其实是生成器的语法糖时,才发现自己平时对生成器几乎没有关注,还是得好好学习一番。

迭代器,Iterator

很多资料迭代器和生成器都是放在一起讲的,两个都是 ES6 推出的高级特性,规范将任何实现了Iterable 接口的对象都称之为可迭代对象,可以通过迭代器Iterator进行消费。

一些内置的类型,如StringArray MapSetarguments对象,NodeList都 实现了Iterable接口,他们的Symbol.iterator属性都实现了迭代器工厂函数:

const arr = [1, 2, 3];
console.log(arr[Symbol.iterator]); // f values() {[native code]}

以上这些都称为可迭代对象,以下这些行为能消费可迭代对象

  • for-of
  • [...arr] const [a,b,c] = arr
  • Array.from
  • new Map(array)new Set(array)
  • Promise.all()Promise.race()
  • yield*

迭代器需要返回一个next()方法,调用该方法返回{done:Boolean,value:any},基于此便可自定义迭代器:

class PetsHome {
  constructor(pets) {
    this.pets = [...pets];
  }
  [Symbol.iterator]() {
    let idx = -1;
    let pets = this.pets.slice();
    return {
      next() {
        idx++;
        return {
          done: idx + 1 > pets.length,
          value: pets[idx],
        };
      },
      return() {
        console.log(`迭代器终止`);
        // done为true表示关闭迭代器,不关的化下次从中断点继续
        return { dont: true };
      },
    };
  }
}

const petsHome = new PetsHome(["dog", "cat", "fish", "bird"]);
for (let pet of petsHome) {
  console.log(pet);
}
// dog
// cat
// fish
// bird
let i = 0;
for (let pet of petsHome) {
  if (i > 2) break;
  console.log(pet);
  i++;
}
// dog
// cat
// fish
// 迭代器终止

生成器,Generator

生成器本质是一个函数,除了箭头函数外,其他任何方式定义的函数,在函数名称前加一个*号, 都能将变成一个生成器。调用生成器函数会产生一个生成器对象,并且这个对象实现了Iterator接口, 具有next()方法(它返回对象的value就是生成器函数的返回值),生成器对象有状态的概念(类似 Promise), 初始状态为suspend,通过yield关键字可以让生成器停止执行,调用next()回复恢复执行

function* spellHello() {
  yield "h";
  yield "e";
  yield "l";
  yield "l";
  yield "o";
}
for (let s of spellHello()) {
  console.log(s);
}

yield关键字是生成器的精髓所在,它只能在生成器的内部使用,它的返回值作为每次调用next()value, 同时还可以yield*操作可迭代对象,增强生成器行为

function* genFn() {
  yield* [1, 2, 3];
  yield* [4, 5, 6];
}
for (let num of genFn()) {
  console.log(num);
}
// 1
// 2
// 3
// 4
// 5
// 6

生成器对象还有return()throw()方法,用以提前终止迭代器

async/await

阮一峰老师的《ES6 标准入门》提到,async函数其实就是Generator的语法糖, 将*换成了async,将yield换成了await,更加的语义化了

function* gen() {
  yield something;
  return;
}
// 类似于
async function f() {
  await something;
  return;
}

async相较于生成器而言有一些改进:

  1. async函数不需要执行器,行为与普通函数一致
  2. 返回值是Promise

最后

迭代器和生成器都是比较高级的特性,在普通的业务开发中几乎不会用到,对他们的理解还有待加深, 也要进一步去探索它们的使用场景