为什么JavaScript在常见的浏览器中没有自己的线程?

时间:2015-06-19 07:53:59

标签: javascript browser architecture software-design

JavaScript并不是多线程的,显然JavaScript甚至没有自己的,但是与其他东西共享一个线程。即使在大多数现代浏览器中,JavaScript通常与绘画,更新样式和处理用户操作位于同一队列中。

为什么?

根据我的经验,如果JavaScript在自己的线程上运行,可以获得极大改善的用户体验,单独由JS不阻止UI呈现或解放复杂或有限的消息队列优化样板(是的,也是你,webworkers!)开发人员必须自己写一篇文章,以便在真正涉及它的时候保持UI响应。

我有兴趣了解控制这种看似不幸的设计决策的动机,从软件架构的角度来看是否有令人信服的理由?

1 个答案:

答案 0 :(得分:18)

用户操作需要JS事件处理程序的参与

用户操作可以触发参与并可能影响用户操作的Javascript事件(点击,焦点事件,关键事件等等),因此在处理用户操作时,单个JS线程无法执行因为,如果是这样,那么JS线程就无法参与用户操作,因为它已经在做其他事情了。因此,浏览器不会处理默认用户操作,直到JS线程可用于参与该过程。

渲染

渲染更复杂。一个典型的DOM修改序列如下:1)由JS修改的DOM,布局标记为脏,2)JS线程完成执行,因此浏览器现在知道JS完成了修改DOM,3)浏览器做布局以重新布局更改的DOM,4浏览器根据需要绘制屏幕。

步骤2)在这里很重要。如果浏览器在每次JS DOM修改后都进行了新的布局和屏幕绘制,那么如果JS实际上要进行一堆DOM修改,那么整个过程可能会非常低效。此外,还会出现线程同步问题,因为如果您在浏览器尝试重新布局和重新绘制的同时让JS修改DOM,则必须同步该活动(例如,阻止某人以便操作可以完成而没有其他线程更改基础数据。)

仅供参考,有一些解决办法可用于强制重新布局或强制从JS代码中重新绘制(不完全是你所要求的,但在某些情况下很有用)。

多个线程访问DOM真的很复杂

DOM本质上是一个大的共享数据结构。浏览器在解析页面时构造它。然后加载脚本和各种JS事件就有机会修改它。

如果您突然有多个JS线程可以同时访问DOM,那么您就会遇到一个非常复杂的问题。你会如何同步访问?您甚至无法编写最基本的DOM操作,该操作涉及在页面中查找DOM对象然后修改它,因为这不是原子操作。在您找到DOM对象和修改时间之间,DOM可能会发生变化。相反,您可能必须获取DOM中至少一个子树的锁,以防止在您操作或搜索它时由其他某个线程更改。然后,在进行修改之后,您必须释放锁并从代码中释放对DOM状态的任何了解(因为一旦释放锁,其他一些线程就可以更改它)。而且,如果你没有正确地做事,你最终可能会出现死锁或各种令人讨厌的错误。实际上,您必须将DOM视为并发的多用户数据存储区。这将是一个复杂得多的编程模型。

避免复杂性

"单线程JS"中有一个统一的主题。设计决定。 保持简单。不需要了解多线程环境和线程同步工具以及调试多个线程,以便编写可靠,可靠的浏览器Javascript。

浏览器Javascript是一个成功的平台的一个原因是因为它对所有级别的开发人员都非常容易访问,并且相对容易学习和编写可靠的代码。虽然浏览器JS可能会随着时间的推移获得更多高级功能(就像我们使用WebWorkers一样),但您可以绝对肯定这些功能将以简单易懂的方式完成,而更先进的开发人员可以完成更高级的功能,但是没有打破任何让事情变得简单的事情。

仅供参考,我在node.js中编写了一个多用户Web服务器应用程序,由于nodejs Javascript的单线程特性,我不断惊讶于服务器设计的复杂程度。是的,有一些事情更难以编写(学习编写大量异步代码的承诺),但是简单的假设是你的JS代码永远不会被另一个请求中断,这大大简化了设计,测试并减少了很难找到并修复并发设计和编码总是令人烦恼的错误。

讨论

当然,第一个问题可以通过允许用户操作事件处理程序在自己的线程中运行来解决,以便它们可以随时发生。但是,然后你立即拥有多线程Javascript,现在需要一个全新的JS基础架构来进行线程同步和全新的bug类。浏览器Javascript的设计者一直决定不打开那个盒子。

如果需要,可以改进渲染问题,但是浏览器代码很复杂。您必须发明一些方法来猜测当运行的JS代码似乎不再更改DOM时(可能有一些ms经过而没有更多更改),因为您必须避免进行重新布局和屏幕绘制立即对每个DOM进行更改。如果浏览器这样做,一些JS操作将比现在慢100倍(100x是一个疯狂的猜测,但关键是他们会慢很多)。并且,您必须在布局,绘图和JS DOM修改之间实现线程同步,这是可行的,但复杂,大量的工作和浏览器实现错误的肥沃土壤。并且,当你通过重新布局或重新绘制并且JS线程进行DOM修改时,你必须决定该做什么(没有一个答案很好)。