是一种特殊的函数,可以按需一个接一个的产生值,可以用来进行异步编程ES6

语法

在 function 后面加 *,函数体内使用 yield

function* myGenerate() {
  yield 1
  yield 2
  return 3
}
 
let g = myGenerate()
g.next()

调用 Generator 函数,返回一个 迭代器对象,里面有 next() 方法,
调用 next() 的结果是一个对象,具有两个属性:

  • value: 产出(yielded)的值
  • done: 如果 generator 函数已执行完成则为 true,否则为 false

迭代器对象的 next 方法的运行逻辑:

  1. 遇到 yield,将 yield 后面的表达式的值作为返回对象的 value,并暂停执行后面的语句
  2. 下一次调用 next 方法时,再继续往下执行,直到遇到下一个 yield 表达式
  3. 继续直到 return 语句为止,并将 return 语句后面的表达式的值,作为返回的对象的 value,同时 done 为 true
  4. 如果没有 return 语句,则返回的对象的 value 属性值为 undefined

可迭代

因为有符合迭代规则的 next(),所以 generator 是可迭代的,满足可迭代对象的所有用法

如可以使用 for…of 遍历它:

for (let value of g) {
  console.log(value) // 1,然后是 2,没有 3
}

注意:没有打印 3,这是因为当 done: true 时,会忽略最后一个 value(其他用法也一样)。因此,如果想要通过 for…of 循环显示所有的结果,必须使用 yield 3 而不是 return 3

NOTE

可迭代用法作用于 generator 时,只会获取 yield 后面的值

yield*

用来在一个 Generator 函数里面执行另一个 Generator 函数

function* g() {
  yield* g1()
  yield* g2()
  yield* g3()
}

next() 传参

next() 可以传参数,将回传赋值给 generator 函数中“上一个” yield 等号前面的变量,也就是作为 yield 语句的返回值

function* gen() {
  let res = yield 1
  console.log(res)
  yield res
}
 
let g = gen()
g.next()
// 执行后返回 {value: 1, done: false}
g.next(2)
// 执行后打印 2
// 然后返回 {value: 2, done: false}
g.next()
// 执行后返回 {value: undefined, done: true}

用途

用来实现可迭代对象的迭代器(Iterator),将 Generator 赋值给 obj[Symbol.iterator],可以使代码更短

如,替换掉 可迭代对象的迭代器

let range = {
  from: 1,
  to: 5,
 
  *[Symbol.iterator]() { // [Symbol.iterator]: function*() 的一种简写
    for (let value = this.from; value <= this.to; value++) {
      yield value
    }
  }
};
 
for(let value of range) {
  console.log(value) // 1,然后 2,然后 3,然后 4,然后 5
}

异步 Generator

在 function* 前面加上 async,然后使用 for await...of 来遍历它

let range = {
  from: 1,
  to: 5,
 
  // 这一行等价于 [Symbol.asyncIterator]: async function*() {
  async *[Symbol.asyncIterator]() {
    for(let value = this.from; value <= this.to; value++) {
 
      // 在 value 之间暂停一会儿,等待一些东西
      await new Promise(resolve => setTimeout(resolve, 1000))
 
      yield value
    }
  }
};
 
(async () => {
 
  for await (let value of range) {
    console.log(value) // 1,然后 2,然后 3,然后 4,然后 5
  }
 
})()

现在,value 之间打印的延迟为 1 秒

Generator 和异步 Generator 之间差异

Generator异步 Generator
声明方式function*async function*
next() 返回值{value:..., done: true/false}resolve 成 {value:..., done: true/false} 的 Promise