JavaScript 因为其异步编程的特性而变得越来越受欢迎。许多库和框架已经为我们封装好了针对浏览器和服务器的单线程异步代码。在 ES6 之前,Promise 和 async/await 是最常用的方式。但是,自 ES6 开始,Generator 也成为一种优雅的异步编程方式。
Generator 简介
在 ES6 中,Generator 是一种函数类型,它可以通过yield
关键字停止函数执行状态,同时也能在恢复函数状态时向外返回值。
-- -------------------- ---- ------- --------- ------------- - ----- -- ----- -- - ----- --- - -------------- ------------------------ -- ------- -- ----- ------ ------------------------ -- ------- -- ----- ------ ------------------------ -- ------- ---------- ----- -----
上面这个 Generator 的例子中,我们通过myG.next()
取回了供外部使用的状态和值。Generator 是一个能够消耗和产出函数状态的函数。
Generator 的异步特性
在 Generator 内部,我们可以使用以下语法来实现异步处理:
function* myGenerator() { const data = yield request('/path/to/api'); // <- 这个请求是异步的 console.log(data); }
如果像上面的代码一样写,我们将能够实现一些非阻塞式的异步执行方式。我们可以分成以下步骤来说明这个过程:
- generator 调用 request。
- request 会初始化一个异步调用,将其推到 event loop 中,然后生成器会 yield request 语句并等待异步响应。
- 当异步请求结束时,代码会继续运行而且会将响应数据作为
data
变量的值返回到yield
的位置上。 - 最后,Generator 继续执行其中的代码。
这种异步操作的幕后能够提供异步执行所需的表现力和性能。
Generator 的异步用例
通过助手库 yield-style 的使用,我们来介绍一些功能强大的异步 use-cases。
用例 1:串行处理异步逻辑
将在运行时响应的结果组合成需要的结果是一种非常好的编程模型。让我们来看一个具有阻塞式嵌套式结构的代码块。
-- -------------------- ---- ------- ------------------ -------- ----- ----- - -- ----- - ------ ----------------- - ------------------ - -------- -------- ----- ----- - -- ----- - ------ ----------------- - ------------------ - ------- - --- - -------- -------- ----- ----- - -- ----- - ------ ----------------- - ----------------- ----- ------ --- --- ---
上面这个代码块是一个错综复杂的层级代码,难以维护和加强。何不换一种方式来写呢?
-- -------------------- ---- ------- --------- ------------------- - --- - ----- ----- - ----- ------------------- ----- - ----- ------------------ - ---------- ----- - ----- ------------------ - -------- - --- - ---------- ------------------ ------ ------- - ---------- - ----------------- - - ----------------------
这个新的 Generator 实现只需很少的额外代码,不仅易于阅读,而且易于调试和维护。使用run
方法来运行外部 Generator 实例,它使用 Promise 来解决异步实现。我们甚至可以使用 try/catch 的块级封装,在异步过程中抓住错误和异常。
用例 2:停止和取消异步操作
停止和取消异步是实现简单而又复杂的一种情况。使用 Generator 可以优雅地解决这个问题。让我们来看一个用于搜索数据的异步实现。
-- -------------------- ---- ------- --------- ------------- - ----- ----------- - ----- ----------------- ----- ------------- - ----- -------------------- ------------ - --------------------- -- ------------- --- -- - ----- ---------- ----- -------- - ---- - ----- ------------------------------ - - --- ----------------- - - ----------- ----- -- --------- ---------------- - --- - ----- ------------- - ----- ----------------------- -- ------------------------------ - ----- --- -------------- --- ---- ----------- - ---- - ------ -------------- - - ---------- - ------------------- --------- ------- ----- - - -------- -------------- - ---------------------------- - ----- - ------------------- ------------------------ -----
你已经在这个代码块中看到我们使用了一个名为 CancellationToken 的块级 variable,并在调用 getSearchQuery 函数时赋值。当信息从输入元素收集完成时,它在为用户提供通知之前等待取消 (如果正在进行) 或值。
借助Generator,我们可以使用简单的 if 语句中止异步逻辑。
总结
在本文中,我们了解到了 Generator 以及与 ES5 异步模式之间的不同之处。我们用 yield-style 库来说明了很多异步 use-cases,如串联依赖关系、异步操作停止、异常处理和取消。有了 Generator 做支撑,你的异步逻辑将更加简单、直观和可读。
上面这些例子仅仅是基础,你仍有很多路要走。你可以进一步研究使用这个底层的行为库提供的许多其他用例的源代码以及相应的实现细节。
通过消除复杂的线程和代码并创建身临其境的应用程序,你可以轻松地创建出现代化的 Web 应用程序。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/65212c6595b1f8cacd8a85ec