ECMAScript 2018 中的 Async Iterator:解决 Promise 并发的万能武器

阅读时长 5 分钟读完

在前端开发中,我们经常会遇到需要处理大量异步操作的情况,比如从服务端获取数据、处理用户输入等。在 ES6 中,Promise 成为了处理异步操作的标准方式,然而当需要同时处理多个 Promise 时,我们常常会遇到一些问题,比如如何控制并发数、如何处理 Promise 的错误等。在 ECMAScript 2018 中,Async Iterator 的出现为解决这些问题提供了一种全新的方案。

Async Iterator 简介

在 ES6 中,我们可以通过 Iterator 对象来遍历集合类型的数据,例如数组、Set、Map 等。而 Async Iterator 则是对 Iterator 的扩展,它可以用于遍历异步生成器函数生成的数据。异步生成器函数是指返回 Promise 的 Generator 函数,例如:

Async Iterator 可以通过 for-await-of 循环来遍历异步生成器函数生成的数据,例如:

-- -------------------- ---- -------
------ ---------- -
  --- ----- ------ ----- -- ----------------- -
    -------------------
  -
-----
-- -------
-- -
-- -
-- -

需要注意的是,Async Iterator 的使用需要在支持 ES2018 规范的环境中才能生效,否则会抛出语法错误。

Async Iterator 解决 Promise 并发的问题

在实际应用中,我们经常需要同时处理多个 Promise,例如从服务端获取多个数据接口的数据。如果使用 Promise.all 来处理,会面临控制并发数和处理错误的问题。而使用 Async Iterator 则可以轻松解决这些问题。

控制并发数

使用 Async Iterator 可以轻松控制并发数,例如我们需要同时获取 10 个数据接口的数据,但是希望每次只处理 3 个 Promise,可以使用以下代码:

-- -------------------- ---- -------
----- --------- ---------------------- -
  ----- -------------- - --
  ----- ------------ - ---------------- -- ------------
  --- ----------------- - --
  ----- -------------------- - -- -
    -- ------------------ - --------------- -
      --------------------
      ----- ----------- - ---------------------
      ----- ----- ------------
      --------------------
    - ---- -
      ----- --- --------------- -- ------------------- ------
    -
  -
-

该代码中,我们使用 fetchAllData 函数来生成一个 Async Iterator,用于遍历多个数据接口的数据。在该函数中,我们定义了 MAX_CONCURRENT 变量来控制每次处理的 Promise 数量,使用 dataPromises 数组来存储所有的 Promise,使用 currentConcurrent 变量来记录当前正在处理的 Promise 数量。在 while 循环中,如果当前正在处理的 Promise 数量小于 MAX_CONCURRENT,就从 dataPromises 数组中取出一个 Promise 并使用 yield await 来等待该 Promise 的结果,并将 currentConcurrent 加 1;如果当前正在处理的 Promise 数量等于 MAX_CONCURRENT,则使用 await new Promise(resolve => setTimeout(resolve, 100)) 来等待 100ms,以让当前正在处理的 Promise 完成一部分后再继续处理下一个 Promise。

使用上述代码,我们可以轻松控制每次处理的 Promise 数量,以达到优化性能的目的。

处理错误

使用 Async Iterator 可以轻松处理 Promise 的错误,例如我们需要同时获取多个数据接口的数据,但是希望在其中一个 Promise 出错时,能够捕获并处理该错误,可以使用以下代码:

-- -------------------- ---- -------
----- --------- ---------------------- -
  ----- ------------ - ---------------- -- ------------------ -- ----
  --- ------ ----------- -- ------------- -
    ----- ---- - ----- ------------
    -- ----- ---------- ------ -
      --------------------
    - ---- -
      ----- -----
    -
  -
-

该代码中,我们使用 fetchAllData 函数来生成一个 Async Iterator,用于遍历多个数据接口的数据。在该函数中,我们使用 dataPromises 数组来存储所有的 Promise,使用 fetch(url).catch(e => e) 来捕获 Promise 的错误,并将错误转换为普通对象。在 for 循环中,我们使用 await dataPromise 来等待 Promise 的结果,如果该 Promise 的结果是一个 Error 对象,则使用 console.error 来输出错误信息;否则,使用 yield data 来将该 Promise 的结果返回。

使用上述代码,我们可以轻松处理 Promise 的错误,以达到更好的错误处理效果。

总结

在 ECMAScript 2018 中,Async Iterator 的出现为解决 Promise 并发的问题提供了一种全新的方案。使用 Async Iterator 可以轻松控制并发数和处理错误,以达到更好的性能和错误处理效果。在实际应用中,我们可以结合 Async Iterator 和其他技术,例如 Promise、Generator、async/await 等,来更好地处理异步操作。

来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/6611fd79d10417a222290470

纠错
反馈