带你读红宝书之生成器

panda2022-12-25 13:54:44前端红宝书 生成器

生成器是什么?

生成器拥有在一个函数内暂停和恢复代码执行的能力,这里值得一说,我们熟悉的异步解决方案async,await就是基于生成器实现的.

一个简单的生成器实例

function* g(){
}

在function关键词之后跟上一个*号之后,那么这个函数就变成了一个生成器函数,在调用这个函数后,会得到一个生成器对象,这个对象实现了Iterator接口,所以具有迭代器的特性.

好的,接下来我们来看一个相对完整的生成器案例.

function* g() {
  yield (() => { console.log(11); return 1 })()
  yield (() => { console.log(22); return 2 })()
  yield (() => { console.log(33); return 3 })()
}
const gn = g()
const timer = setInterval(() => {
  const val = gn.next()
  if (val.done) clearInterval(timer)
  console.log(val);
}, 1000);

总的来看,可以这样理解,生成器内遇到yield会暂停函数的执行,直到你调用next方法函数才会恢复执行,在遇到下一个yield时又会暂停执行,然后就是循环这个操作了.

yield关键字还可以作为输入输出

这个关键字可以让你每一次调用next时的入参在外部传入,而且next的返回值也可以有yield指定,使用方式也很简单.

来看输入

// 输入
function* gen() {
  console.log('start');
  console.log(yield);
  console.log(yield);
  console.log(yield);
}
const g = gen()
g.next()
g.next(1)
g.next(2)
g.next(3)

这样我们就可以在外部传入参数来执行函数,这里注意第一次调用next不会获取你的入参,它的作用是让你的生成器函数开始执行.

接下来是输出:

// 输出
function* gen() {
  yield "嘿嘿嘿1"
  yield "嘿嘿嘿2"
  yield "嘿嘿嘿3"
  yield* [1,2,3,4]
}
const g = gen()
console.log(g.next().value);
console.log(g.next().value);
console.log(g.next().value);
console.log(g.next().value);
console.log(g.next().value);
console.log(g.next().value);
console.log(g.next().value);

这就是yield输入输出的功能了;你可能注意到了,在上边的案例中,我们使用*来增强yield,这种方式可以让yield产生出可迭代对象,其实这和多写几行yield没什么区别.

使用生成器来改写迭代器

我们可以使用生成器来配合迭代器

class P {
  constructor() {
    this.values=[1,2,3,4]
  }
  *[Symbol.iterator]() {
   yield* this.values
  }
}

wow,如此的简洁

提前终止生成器

你可以直接在生成器对象上调用return这个api来提前终止,每个生成器对象上都会有这个api

function* gen() {
  yield "嘿嘿嘿1"
  yield "嘿嘿嘿2"
  yield "嘿嘿嘿3"
  yield* [1,2,3,4]
}
const g=gen()
g.next()
g.return()
// g.next() 一旦生成器进入关闭状态是不能恢复的

总结

生成器具有暂停代码执行的神奇功能,我们可以用它来满足一些特殊的场景.

Last Updated 2023-01-07 16:28:39