作者 | Dylan Kerler
译者 | 王强
策划 | 李俊辰
社区中关于 JavaScript 中生成器(generator)类型的讨论很少见,这是因为我们很少碰到实际需要使用它的场景。但这并不能否定这一特性的实用性——因为当你真的遇上这类场景时,就会发现生成器真的很好用了。
就像编程领域中的大多数事物一样,生成器类型只是一种工具;具体来说,它是一种专业工具。
我们来看一个实践中生成器的示例,然后一步步分析,看看它是如何工作的:
上面是定义的一个生成器。你会发现它与常规函数非常相似,区别就是它有一个 * 和一个 yield 关键字。* 告诉 JavaScript 这是一个生成器函数,然后来看 yield。首先,我们看一个生成器运行示例:
这里的 someGenerator 返回了一个 iterator,使我们可以访问 next 方法。每次调用 next 时,函数将运行我们的代码,直到遇到 yield 语句为止。当我们遇到 yield 语句时将暂停执行,直到 next 被再次调用。当 someGenerator 完成执行后,下次我们调用 next 时将收到一个对象,该对象有一个 done 键,其值设置为 true。
很整洁是吧?其实返回的 iterator 允许我们做的事情还有很多。我们还可以访问 for…of 语句以及其他 iterator 方法,例如 spread 运算符:
现在,我们了解了生成器的基础使用知识,下面来看一些用例。
一个常见的用例是维护基于一个索引的 id 生成器的状态。假设我们有一个项目的映射 / 对象,还想公开一个函数,允许用户向该映射添加一个项目——每个项目都应根据插入顺序获得唯一的 ID。我们可以通过生成器来实现 ID 的生成:
另一个示例是将 UX 流程抽象为一个函数。假设我们有一个 UX 设计;用户单击一个按钮,然后进行一些计算,完成计算后我们要显示另一个按钮,单击该按钮会执行更多计算,然后刷新窗口。
我们可以将所有这些都放到一个函数中,但这可能会造成混乱。相比之下,由于我们知道 UX 设计流程的顺序,因此可以使用生成器解决:
这里我们成功地隔离了 UX 设计和逻辑,从而简化了测试,增强了可读性和维护性。每次完成计算时,我们都会在用户界面中显示下一个阶段。
小结
一般情况下,开发者不需要用到生成器,但是在某些特定场景中,当你使用生成器时会很喜欢它的——它们可以帮助你简化迭代过程,并为需要延迟计算有序值的场景提供一个整洁的解决方案。