Generator 是一种非常强力的语法,但它的使用并不广泛(参见下图 twitter 上的调查!)。为什么这样呢?相比于 async/await,它的使用更复杂,调试起来也不太容易(大多数情况又回到了从前),即使我们可以通过非常简单的方式获得类似体验,但是人们一般会更喜欢 async/await。
然而,Generator 允许我们通过 yield 关键字遍历我们自己的代码!这是一种超级强大的语法,实际上,我们可以操纵执行过程!从不太明显的取消操作开始,让我们先从同步操作开始吧。
批处理 (或计划)
执行 Generator 函数会返回一个遍历器对象,那意味着通过它我们可以同步地遍历。为什么我们想这么做?原因有可能是为了实现批处理。想象一下,我们需要下载 1000 个项目,并在表格中逐行的显示它们(不要问我为什么,假设我们不使用框架)。虽然立刻展示它们没有什么不好的,但有时这可能不是最好的解决方案 —— 也许你的 MacBook Pro 可以轻松处理它,但普通人的电脑不能(更别说手机了)。所以,这意味着我们需要用某种方式延迟执行。
请注意,这个例子是关于性能优化,在你遇到这个问题之前,没必要这样做 ——过早优化是万恶之源!
没有什么区别是吧?那么,这里的区别在于,现在我们可以在不改变源代码的情况下以不同方式运行这个函数。实际上,正如我之前提到的,没有必要等待,我们可以同步执行它。所以,来调整下我们的代码。在每个 yield 后边加一个 4 ms(JavaScript VM 中的一个心跳) 的延迟怎么样?我们有 1000 个项目,渲染将需要 4 秒 —— 还不错,假设我想在 2 秒之内渲染完毕,很容易想到的方法是每次渲染 2 个。突然使用 Promise 的解决方案将变得更加复杂 —— 我们必须要传递另一个参数:每次渲染的项目个数。通过我们的执行器,我们仍然需要传递这个参数,但好处是对我们的 renderItems 方法完全没有影响。
正如你所看到的,我们可以轻松改变每批处理项目的个数,不去考虑执行器,回到正常的同步执行方式 —— 所有这些都不会影响我们的 renderItems 方法。
取消
我们来考虑下传统的功能 —— 取消。在我 ) 这篇文章中已经详细谈到了。所以我会使用其中一些代码:
这里最好的部分是我们可以取消所有还没来得及执行的请求(也可以给我们的执行器传递类似AbortController 的对象参数,所以它甚至可以取消当前的请求!),而且我们没有修改过自己业务逻辑中的一行的代码。
暂停/恢复
另一个特殊的需求可能是暂停/恢复功能。你为什么想要这个功能?想象一下,我们渲染了 1000 行数据,而且速度非常慢,我们希望给用户提供暂停/恢复渲染的功能,这样他们就可以停止所有的后台工作读取已经下载的内容了。让我们开始吧!
调用这个执行器,可以给我们返回一个具有暂停/恢复功能的对象,所有这些都可以轻松得到,还是使用我们之前的业务代码!所以,如果你有很多"沉重"的请求链,需要耗费很长时间,而你想给你的用户提供暂停/恢复功能的话,你可以随意在你的代码中实现这个执行器。
错误处理
我们有个神秘的 onRejected 调用,这是我们这部分谈论的主题。如果我们使用正常的 async/await 或 Promise 链式写法,我们将通过 try/catch 语句来进行错误处理,如果不添加大量的逻辑代码就很难进行错误处理。通常情况下,如果我们需要以某种方式处理错误(比如重试),我们只是在 Promise 内部进行处理,这将会回调自己,可能再次回到同样的点。而且,这还不是一个通用的解决方案 —— 可悲的是,在这里甚至 Generator 也不能帮助我们。我们发现了 Generator 的局限 —— 虽然我们可以控制执行流程,但不能移动 Generator 函数的主体;所以我们不能后退一步,重新执行我们的命令。一个可行的解决方案是使用command pattern,它告诉了我们 yield 结果的数据结构 —— 应该是我们需要执行此命令需要的所有信息,这样我们就可以再次执行它了。所以,我们的方法需要改为:
正如你所看到的,这使得我们不清楚发生了什么 —— 所以,也许最好是写一些 wrapWithRetry 方法,它会检查 catch 代码块中的错误类型并再次尝试。但是我们仍然可以做一些不影响我们功能的事情。例如,我们可以增加一个关于忽略错误的策略 —— 在 async/await 中我们不得不使用 try/catch 包装每个调用,或者添加空的 .catch(() => {}) 部分。有了 Generator,我们可以写一个执行器,忽略所有的错误。
关于 async/await
Async/await 是现在的首选语法(甚至 也谈到了它 ),这也是未来。但是,Generator 也在 ECMAScript 标准内,这意味着为了使用它们,除了写几个工具函数,你不需要任何东西。我试图向你们展示一些不那么简单的例子,这些实例的价值取决于你的看法。请记住,没有那么多人熟悉 Generator,并且如果在整个代码库中只有一个地方使用它们,那么使用 Promise 可能会更容易一些 —— 但是另一方面,通过 Generator 某些问题可以被优雅和简洁的处理。
总结
以上所述是小编给大家介绍的在 JavaScript 中使用 Generator的方法。编程之家 jb51.cc 收集整理的教程希望能对你有所帮助,如果觉得编程之家不错,可分享给好友!感谢支持。
原文链接:https://www.f2er.com/js/34426.html