生成器知识点总结

199 阅读3分钟

「这是我参与2022首次更文挑战的第11天,活动详情查看:2022首次更文挑战」。

什么是生成器

生成器是ES6新增的一种函数控制的方案,它可以灵活地控制函数什么时候执行、什么时候暂停。 生成器函数也是一个函数,它和普通函数的区别:

(1)生成器函数需要在function后面加*

(2)生成器函数通过关键字yield来控制函数的执行与暂停

(3)生成器函数返回一个Generator(生成器)

生成器本质上是一个特殊的迭代器。

生成器函数

有以下代码可知,foo是个生成器函数,因为它符合生成器函数的条件: (1)function后面加* (2)使用yield来控制函数的执行与暂停 (3)当调用foo函数时,会返回一个生成器对象,它是一个特殊的迭代器,我们可以调用next方法。

function* foo() {
  console.log('函数开始执行');

  const value1 = 100
  console.log('第一段代码:', value1);
  yield

  const value2 = 200
  console.log('第二段代码:', value2);
  yield

  const value3 = 300
  console.log('第三段代码:', value3);
  yield

  console.log('函数执行结束');
}
// 调用生成器函数时,会返回给我们一个生成器对象
const generator = foo()

// 开始执行第一段代码
generator.next()

// 开始执行第二段代码
generator.next()
generator.next()
generator.next()
generator.next()
generator.next()
generator.next()

生成器函数的执行流程

当遇到yeild时暂停函数的执行,当遇到return时终止函数的执行。

function* foo() {
  console.log('函数开始执行');

  const value1 = 100
  console.log('第一段代码:', value1);
  yield value1

  const value2 = 200
  console.log('第二段代码:', value2);
  yield value2

  const value3 = 300
  console.log('第三段代码:', value3);
  yield value3

  console.log('函数执行结束');
  return '123'
}

const generator = foo()
console.log('返回值1:', generator.next());
console.log('返回值2:', generator.next());
console.log('返回值3:', generator.next());
console.log('返回值4:', generator.next());

生成器传递参数

通过yield我们让函数可以暂停分段执行。函数可以传递参数,那么我们如何给分段的函数传递参数呢?

我们在调用next时,可以给它传递参数,那么这个参数会作为上一个yield语句的返回值

function* foo() {
  console.log('函数开始执行');
  const value1 = 100
  console.log('第一段代码:', value1);
  const n = yield value1

  const value2 = 200 * n 
  console.log('第二段代码:', value2);
  const count = yield value2

  const value3 = 300 * count
  console.log('第三段代码:', value3);
  yield value3

  console.log('函数执行结束');
  return '123'
}

const generator = foo()
console.log(generator.next());
console.log(generator.next(10)); // 第二个next的参数作为第一个yield的返回值
console.log(generator.next(20));

那么我们想要给第一段传递参数呢?我们可以在函数调用的时候传递参数。

function* foo(num) {
  console.log('函数开始执行');
  const value1 = 100 * num
  console.log('第一段代码:', value1);
  const n = yield value1

  const value2 = 200 * n 
  console.log('第二段代码:', value2);
  const count = yield value2

  const value3 = 300 * count
  console.log('第三段代码:', value3);
  yield value3

  console.log('函数执行结束');
  return '123'
}

const generator = foo(5)
console.log(generator.next());
console.log(generator.next(10));
console.log(generator.next(20));

生成器提前结束——return函数

我们可以使用return让生成器提前结束,之后再继续调用next不会继续生成值了。

function* foo(num) {
  console.log('函数开始执行');

  const value1 = 100 * num
  console.log('第一段代码:', value1);
  const n = yield value1

  const value2 = 200 * n
  console.log('第二段代码:', value2);
  const count = yield value2

  const value3 = 300 * count
  console.log('第三段代码:', value3);
  yield value3

  console.log('函数执行结束');
  return 123
}

const generator = foo(10)
console.log(generator.next());
console.log(generator.return(20));

生成器抛出异常——throw函数

我们可以在生成器内部捕获异常。

function* foo() {
  console.log('代码开始执行');

  const value1 = 100
  try {
    yield value1
  } catch (error) {
    console.log('捕捉到异常情况:', error);
    yield 123
  }
  console.log('第二段代码继续执行');
  const value2 = 200
  yield value2
  console.log('代码执行结束');
}

const generator = foo()
console.log(generator.next());
console.log(generator.throw('error message')); 
console.log(generator.next());