ES6 中的 Generator 函数详解

Generator 函数是 ES6 中引入的新的函数类型,它可以让函数在执行过程中被暂停和恢复。Generator 函数是一个状态机,封装了多个内部状态,每次调用 Generator 函数都会返回一个值,同时暂停函数执行,等待重新调用。Generator 函数的返回值是一个指向内部状态的指针对象(Iterator)。

基本用法

定义一个 Generator 函数,需要在函数名前面加上 *

function* genFunc() {
  yield 'a'
  yield 'b'
  yield 'c'
}

const genObj = genFunc()

console.log(genObj.next())  // {value: "a", done: false}
console.log(genObj.next())  // {value: "b", done: false}
console.log(genObj.next())  // {value: "c", done: false}
console.log(genObj.next())  // {value: undefined, done: true}

上面代码中,定义了一个 Generator 函数 genFunc ,然后使用 next() 方法逐个调用函数,可以看到每次执行函数到 yield 关键字时都会暂停并返回结果。

恢复执行

调用 next() 方法时可以传入参数,这个参数就是上一个 yield 关键字的返回值。Generator 函数会将这个参数赋值给上一个 yield 表达式,并且从这个位置继续执行。

function* star() {
  const a = yield 'a'
  const b = yield 'b'
  console.log(a, b)
}

const gen = star()
console.log(gen.next())  // {value: "a", done: false}
console.log(gen.next('Hello'))  // {value: "b", done: false}
console.log(gen.next('World'))  // Hello World
console.log(gen.next())  // {value: undefined, done: true}

上面代码中,第一次调用 next() 方法时没有传入参数,生成器函数执行到第一个 yield 关键字处,并返回结果 a。第二次调用 next('Hello') 方法时将参数 "Hello" 传入,这个参数就是上一个 yield 表达式的返回值,代码继续执行到第二个 yield 关键字处,并返回结果 b。第三次调用 next('World') 方法时将参数 "World" 传入,代码继续执行到函数结束,控制台输出 Hello World

使用 for...of 语句

可以使用 for...of 语句直接循环遍历 Generator 函数的每一个值。

function* colors() {
  yield 'Red'
  yield 'Green'
  yield 'Blue'
}

for (let color of colors()) {
  console.log(color)
}

上面代码中,Generator 函数 colors() 定义了三个 yield 关键字,使用 for...of 循环逐个输出三个颜色。

使用 Generator 实现异步操作

Generator 函数可以使用 yield 关键字暂停函数的执行过程,等待其他异步操作完成后再继续执行,这样可以方便地实现异步操作。

function fetchData(url) {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve(`Data received from ${url}`)
    }, 2000)
  })
}

function* asyncFunc() {
  const data1 = yield fetchData('URL1')
  console.log(data1)
  const data2 = yield fetchData('URL2')
  console.log(data2)
  const data3 = yield fetchData('URL3')
  console.log(data3)
}

const asyncGen = asyncFunc()
const promise = asyncGen.next().value

promise.then(result1 => {
  asyncGen.next(result1).value.then(result2 => {
    asyncGen.next(result2).value.then(result3 => {
      asyncGen.next(result3)
    })
  })
})

上面代码中,定义了 fetchData 函数,模拟异步请求数据并返回一个 Promise 对象。然后定义了一个 asyncFunc Generator 函数,使用 yield 关键字分别接收三个异步操作的结果,并输出到控制台。接着定义了一个 asyncGen 对象,调用 next() 方法后可以执行到第一个异步操作。使用 Promise 对象的链式调用完成异步操作,最终输出结果。

总结

Generator 函数是一种新的函数类型,可以暂停函数执行并返回值,从而实现异步操作。Generator 函数是一种强大的工具,良好的运用可以提高代码的可读性和可维护性。

来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/65b7150badd4f0e0fffae2b0