首页 > 解决方案 > 浏览器的 JavaScript 和多线程用于异步操作?

问题描述

我正在尝试在 indexedDB 对象存储中布置数据,并使用 Promise.all 来提取数据、构建 HTML 并将其添加到单页 Web 应用程序中选项卡式显示的不同部分。

如果 Promise.all 用于从不同的对象存储或同一存储的不同键范围中提取数据,然后构建 HTML 片段并在解析每个单独的 Promise 之前插入它们,那么浏览器是否真的同时执行这些步骤以完成该过程更快?

更具体地说,对于显示中每个选项卡的数据提取有一个承诺。如果事务成功完成,则数据将传递给构建和插入 HTML 的函数,当它返回时,promise 将解析。每个选项卡的承诺都在 Promise.all 中进行分组,当它解决时,程序导航到第一个选项卡并显示它。

这真的是同时处理多个事情,还是只是提供一种计时方法,仅在已知所有选项卡的数据和 HTML 已成功收集和构建后才显示第一个选项卡?

这是否比使用 then 语句链接承诺一个接一个地运行更快,但不比单独启动每个承诺并在第一个选项卡的承诺上放置一个 then 来显示它更快?

我知道 JS 是一种单线程语言,但其中一些方法的文档显示为“在单独的线程中......”;所以,我不太明白浏览器是否同时执行一些事情。

谢谢你。

标签: javascriptmultithreadingpromise

解决方案


首先,我们只是规定不使用 webWorker 线程,所以我们只是在谈论网页中的常规 Javascript。

在这种情况下,在任何给定时间只有一个 Javascript 线程在运行,并且整个系统是事件驱动的(稍后会详细介绍)。

因此,在运行实际的 Javascript 代码时,一次只能运行一个。但是,一旦您进行具有本地代码支持的非阻塞异步实现的函数调用,然后 Javascript 调用本地代码,异步操作就会启动,然后它立即将控制权返回给 Javascript 解释器所以更多的Javascript可以运行。通过这种方式,您可以一次启动多个异步操作,这些操作将独立于 Javascript 解释器进行。

它们的独立程度和并行程度取决于这些异步操作的实现。如果他们都在访问同一个数据库,那么可用的数据库操作之间可能存在或不存在一些真正的并行性——这完全取决于数据库的实现。

现在,假设您确实启动了多个数据库操作,并且您正在跟踪它们何时全部完成Promise.all()。当每一个完成时,它会在 JS 事件队列中插入一个事件。当 JS 解释器无事可做时,它将从事件队列中拉出下一个事件并运行与完成该异步操作相关的回调。使用时Promise.all(),该回调将(除其他外)将该单个操作标记为已完成并存储其结果以供以后访问。当您跟踪的所有操作都Promise.all()以这种方式完成时,Promise.all()返回的 Promise 将解析,您可以访问结果数组。

现在到你的具体问题...

如果 Promise.all 用于从不同的对象存储或同一存储的不同键范围中提取数据,然后构建 HTML 片段并在解析每个单独的 Promise 之前插入它们,那么浏览器是否真的同时执行这些步骤以完成该过程更快?

如果每个异步操作都能够有效地与其他操作并行运行(在本机代码级别),那么如果这些操作并行运行,那么完成的总时间将比按顺序运行的要快。

这真的是同时处理多个事情,还是只是提供一种计时方法,仅在已知所有选项卡的数据和 HTML 已成功收集和构建后才显示第一个选项卡?

这取决于特定的异步操作,以及它们中的多个是否可以并行运行。通常,他们可以,但并非总是如此。

这是否比使用 then 语句链接承诺一个接一个地运行更快,但不比单独启动每个承诺并在第一个选项卡的承诺上放置一个 then 来显示它更快?

通常,是的。

我知道 JS 是一种单线程语言,但其中一些方法的文档显示为“在单独的线程中......”;所以,我不太明白浏览器是否同时执行一些事情。

浏览器将您的 Javascript(实际 Javascript 指令的执行)作为单线程(此处忽略 webWorkers)运行,没有并行性。但是,当您调用异步操作时,该操作在本机代码中具有实现,并且其背后的本机代码可以自由使用线程或其他异步、非阻塞 OS API/工具来完成其工作。这可能允许单独的异步调用之间的并行性,从而允许多个调用并行进行。

IndexedDB接口包含许多异步接口,这意味着它是事件驱动的,并且必须与一些本机代码异步运行。您必须在给定浏览器中测试该数据库的给定实现,以查看它同时并行处理多个正在进行的请求的能力。每个浏览器实现可能具有不同的特征。


推荐阅读