# Generator & async/await原理

# Generator

Generator 函数是一个状态机,封装了多个内部状态。

执行 Generator 函数会返回一个遍历器对象,可以依次遍历 Generator 函数内部的每一个状态,但是只有调用next方法才会遍历下一个内部状态,所以其实提供了一种可以暂停执行的函数。yield表达式就是暂停标志。

function* helloWorldGenerator() {
  yield 'hello';
  yield 'world';
  return 'ending';
}
var hw = helloWorldGenerator();

调用及运行结果:

hw.next()  // { value: 'hello', done: false }
hw.next()  // { value: 'world', done: false }
hw.next()  // { value: 'ending', done: true }
hw.next()  // { value: undefined, done: true }

由结果可以看出,Generator函数被调用时并不会执行,只有当调用next方法、内部指针指向该语句时才会执行,即函数可以暂停,也可以恢复执行。

每次调用遍历器对象的next方法,就会返回一个有着valuedone两个属性的对象。

  • value属性表示当前的内部状态的值,是yield表达式后面那个表达式的值;
  • done属性是一个布尔值,表示是否遍历结束。

也可以通过给next()传参, 让yield具有返回值

function* myGenerator() {
  console.log(yield '1')  //test1
  console.log(yield '2')  //test2
  console.log(yield '3')  //test3
}

// 获取迭代器
const gen = myGenerator();

gen.next()
gen.next('test1')
gen.next('test2')
gen.next('test3')

Generator 函数的语法 (opens new window)

# async/await 实现

一句话,它就是 Generator 函数的语法糖。

ES7 中引入了 async/await,这种方式能够彻底告别执行器和生成器,实现更加直观简洁的代码。

根据 MDN 定义, async 是一个通过异步执行并隐式返回 Promise 作为结果的函数。

可以说 async 是Generator函数的语法糖,并对Generator函数进行了改进。

const foo = async () => {
    let response1 = await fetch('https://xxx') 
    console.log('response1')
    console.log(response1)
    let response2 = await fetch('https://xxx') 
    console.log('response2')
    console.log(response2)
}

一比较就会发现,async函数就是将 Generator 函数的星号(*)替换成async,将yield替换成await,仅此而已。

async函数对 Generator 函数的改进,体现在以下四点:

  1. 内置执行器:async不需要手动调用next()就能自动执行下一步
  2. 更好的语义:async和await,比起星号和yielz,语义更清楚了。
  3. 更广的适用性:co模块约定,yield命令后面只能是 Thunk 函数或 Promise 对象,而async函数的await命令后面,可以是 Promise 对象和原始类型的值
  4. 返回值是 Promise:async函数返回值是Promise对象,比 Generator 函数返回的 Iterator 对象方便,可以直接使用 then() 方法进行调用。