tk挠痒痒网址发布页-秘密武器
历史搜索

深究 JavaScript 中的生成器

游客2025-05-15 00:33:23
目录文章目录
  1. 前言
  2. 一个例子了解生成器
  3. 基本概念
  4. 如何理解 Generator 函数是状态机?
  5. next 传递参数
  6. 与 Iterator 接口的关系
  7. 提前终止生成器
  8. next()、throw()、return() 的共同点
  9. yield* 表达式

深究 JavaScript 中的生成器 1

在上面的代码中,执行 next 函数,使得 try 代码块开始执行,再调用 return 方法,就会开始执行 finally 代码块,然后等待执行完毕,再返回 return 方法指定的返回值。

throw

throw() 方法会在暂停的时候将一个提供的错误注入到生成器对象中。如果错误未被处理,生成器就会关闭。

在很多的资料中都说的很复杂,其实就很简单:

有错误你就给我一个 catch 来处理掉,不然你就给我退出,就是这么霸道。

function* gen(){
    console.log("state1");
    let state1 = yield "state1";
    console.log("state2");
    let state2 = yield "state2";
    console.log("end");
}
let g = gen();
g.next();
g.throw();

在上面的代码中,throw 方法提出的错误,没有被处理,因此会被直接退出,因此上面的代码只会输出 state1 ,然后报错

注意:可以给 throw 方法传递参数,用来解释错误。

g.throw(new Error('出错了!'))

next()、throw()、return() 的共同点

到这里遍历器对象的 3 个方法,已经都涉及过了,虽然他们的功能各不相同,或者说完全没有关系,但是他们的本质确实在做同一件事,“采用语句替换 yield 表达式”。

next 是将 yield 表达式替换成一个值。

throw是将 yield 表达式替换成 throw 语句。

gen.throw(new Error('出错了')); // Uncaught Error: 出错了
// 相当于将 let result = yield x + y
// 替换成 let result = throw(new Error('出错了'));

return 是将 yield 表达式替换成 return 语句

yield* 表达式

带星号的 yield,可以增强yield的行为,使它能够迭代一个可迭代对象,从而一次产出一个值,这也叫委托迭代。通过这样的方式,能将多个生成器连接在一起。

function * anotherGenerator(i) {
  yield i + 1;
  yield i + 2;
  yield i + 3;
}

function * generator(i) {
  yield* anotherGenerator(i);
}

var gen = generator(1);

gen.next().value; // 2
gen.next().value; // 3
gen.next().value; // 4

几个注意点:

  1. 任何数据结构只要有 Iterator 接口,就可以被yield*遍历。
  2. 如果被代理的 Generator 函数有return语句,那么就可以向代理它的 Generator 函数返回数据。

使用 yield* 实现递归算法

实现递归算法,这也是 yield* 最有用的地方,此时生成器可以产生自身。

function* nTimes(n) {
    if (n > 0) {
        yield* nTimes(n - 1);
        yield n - 1;
    }
}
for (const x of nTimes(3)) {
    console.log(x);
}
// 0 1 2

上面的代码中,每个生成器首先会从新创建的生成器对象产出每个值,然后再产出一个整数。

本文内容就到这里结束了,关于生成器的核心应用异步编码模式以及回调问题,将在下篇总结。

非常感谢您的阅读,欢迎提出你的意见,有什么问题欢迎指出,谢谢!

标签:ES6

本文是由用户"游客"发布,所有内容的版权归原作者所有。没有经过书面许可,任何单位或个人不得以任何形式复制、转载、引用本网站的内容。否则将追究法律责任。

相关专题