在没有 I/O 的情况下,javascript(在浏览器中)中的 async/promises 是否有益?

Are async/promises in javascript (in the browser) beneficial where there's no I/O?

我正在尝试为 json-api 找到一个好的 deserializer/denormalizer(事实证明这非常困难)。

我遇到过几个示例,其中反序列化过程(基本上只是对关系进行反规范化和展平属性)被定义为异步函数。 Here's one such example,但我发现了很多。

现在,我对 node/javascript 的理解是,它基于系统 I/O 绑定,因此它的设计使得操作应该是非阻塞的,以便可以在期间安排其他操作I/O 这样我们就得到了并发操作。

然而,我不明白的是像这样的解串器中的用法。我们在反序列化时拥有完整的有效负载,没有任何 I/O 发生。我只能猜测作者假设关系查找可以同时发生,但是,由于 javascript 仍然是单线程的,我看不出这如何以任何方式提高性能。

在我看来,这只是使确定性操作成为非确定性操作(因为我想除了反序列化之外,时间表还可以安排 其他 操作)。

我是不是漏掉了什么?使这个异步真的有好处吗?我不是前端(或节点)开发人员,所以我觉得我错过了一些东西(因为我已经看到这种模式在反序列化器中使用了很多)

这将是 运行 在浏览器中(不是节点后端)如果有任何不同的话。

看来,您作为示例提到的库的作者没有正确使用 async / await:

 // see: https://github.com/wopian/kitsu/blob/master/packages/kitsu-core/src/deattribute/index.js

 // v does await nothing, as it receives an array
 //                v unneccessary
 await data.map(async el => deattribute(el))

这里根本没有理由使用 async / await,所以我怀疑它在库中是否有任何用途。

Are async/promises in javascript (in the browser) beneficial where there's no I/O?

没有。尽管 promise 总是异步解决的,它们仍然会在所谓的微任务队列中结束(在浏览器中),它会在浏览器重新渲染之前被清空,因此调用异步函数不会帮助你解冻 UI。

I can only guess that the author assumes that the relationship lookups could all happen concurrently, however, since javascript is still single threaded, I can't see how this could in any way improve performance.

我同意,这根本不会提高性能。

It seems to me this is just making a deterministic operation non deterministic (since I suppose the schedule could also schedule other operations besides the deserialization).

不,它不能,因为不涉及可以将引擎从当前任务中解放出来的异步 IO。因此它仍然会运行以阻塞的方式。

我想到的一个原因是分配 CPU 负载。可能将繁重的任务拆分成更小的任务。

让我为您提供一个示例场景。假设您出于某种原因有一个包含多个 JSON 字符串的数组。你可以这样做:

array = json_array.map(json => JSON.parse(json));

这将阻止所有其他 JavaScript,直到整个执行完成。如果解析器提供异步接口,您允许用户事件和其他 JavaScript 代码在每个元素的解析之间 运行。

array = await Promise.all(json_array.map(json => deserialise(json)));

这基本上将每一个 JSON 反序列化分解成它自己的任务。

您可能认为如果您有一个大的 JSON 字符串而不是数组,这将不起作用。但是,您必须记住 JSON 反序列化基本上是一个递归调用,直到它达到主要数据类型。我只能猜测这在内部也被用于将整个 JSON 反序列化过程拆分为微任务。主要目的是保持应用程序响应。

note: As . The linked library tries to do this, but suffers from immediately resolved promise blocking. So there is no benefit in using the linked library. Which appends the resolved promises before other browser tasks, rendering the UI still useless.

我将使用 JSFiddle of Kaiido () 的调整版本作为示例:

const timer = (ms) => new Promise(resolve => setTimeout(resolve, ms));
var toggle;
  
onclick = async function updateBg() {
  // simulate an recurring function that would block
  // 5 seconds when ran synchronously
  const start1 = performance.now();
  async function recurringFunction() {
    const start2 = performance.now();
    console.log('fired');

    // simulate a run duration of a few ms each time called
    while (performance.now() - start2 < 5);

    // make recuring calls for ~5 seconds
    if (performance.now() - start1 < 5000) {
      // pass control back to the JavaScript engine by waiting 0ms
      await timer(0); 
      return recurringFunction();
    }
  }

  // do something before JSON parsing
  document.body.style.background =
    (toggle = !toggle) ? 'LightSalmon' : 'LightCoral';

  // parse the JSON
  await recurringFunction();

  // do something with the result
  document.body.style.background = 'PaleGreen';
}
html, body {
  height: 100%;
  width: 100%;
}
click the background to toggle its colour