为什么 JavaScript 在普通浏览器中没有自己的线程? [英] Why doesn't JavaScript get its own thread in common browsers?

查看:21
本文介绍了为什么 JavaScript 在普通浏览器中没有自己的线程?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Not enough that JavaScript isn't multithreaded, apparently JavaScript doesn't even get its own but shares a thread with a load of other stuff. Even in most modern browsers JavaScript is typically in the same queue as painting, updating styles, and handling user actions.

这是为什么?

根据我的经验,如果 JavaScript 在自己的线程上运行,则可以获得极大改善的用户体验,单独通过 JS 不阻塞 UI 渲染或解放复杂或有限的消息队列优化样板(是的,还有你,网络工作者!)开发人员必须自己编写代码,以便在真正涉及到 UI 时始终保持 UI 响应.

From my experience an immensely improved user experience could be gained if JavaScript ran on its own thread, alone by JS not blocking UI rendering or the liberation of intricate or limited message queue optimization boilerplate (yes, also you, webworkers!) which the developer has to write themselves to keep the UI responsive all over the place when it really comes down to it.

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

I'm interested in understanding the motivation which governs such a seemingly unfortunate design decision, is there a convincing reason from a software architecture perspective?

推荐答案

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

用户操作可以触发参与并可能影响用户操作的 Javascript 事件(点击、焦点事件、按键事件等...),很明显,在处理用户操作时,单个 JS 线程无法执行,因为,如果是这样,则 JS 线程无法参与用户操作,因为它已经在做其他事情.因此,在 JS 线程可参与该过程之前,浏览器不会处理默认的用户操作.

User Actions Require Participation from JS Event Handlers

User actions can trigger Javascript events (clicks, focus events, key events, etc...) that participate and potentially influence the user action so clearly the single JS thread can't be executing while user actions are being processed because, if so, then the JS thread couldn't participate in the user actions because it is already doing something else. So, the browser doesn't process the default user actions until the JS thread is available to participate in that process.

渲染比较复杂.一个典型的 DOM 修改顺序是这样的:1) DOM 被 JS 修改,布局标记为脏,2) JS 线程完成执行,因此浏览器现在知道 JS 完成了对 DOM 的修改,3) 浏览器进行布局以重新布局更改后的 DOM,4) 浏览器根据需要绘制屏幕.

Rendering is more complicated. A typical DOM modification sequence goes like this: 1) DOM modified by JS, layout marked dirty, 2) JS thread finishes executing so the browser now knows that JS is done modifying the DOM, 3) Browser does layout to relayout changed DOM, 4) Browser paints screen as needed.

步骤 2) 在这里很重要.如果浏览器在每次 JS DOM 修改后都进行新的布局和屏幕绘制,如果 JS 真的要进行一堆 DOM 修改,那么整个过程可能会非常低效.另外,还会有线程同步问题,因为如果在浏览器尝试重新布局和重绘的同时让 JS 修改 DOM,则必须同步该活动(例如阻止某人,以便操作可以在没有另一个线程正在更改底层数据).

Step 2) is important here. If the browser did a new layout and screen painting after every single JS DOM modification, the whole process could be incredibly inefficient if the JS was actually going to make a bunch of DOM modifications. Plus, there would be thread synchronization issues because if you had JS modifying the DOM at the same time as the browser was trying to do a relayout and repaint, you'd have to synchronize that activity (e.g. block somebody so an operation could complete without the underlying data being changed by another thread).

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

FYI, there are some work-arounds that can be used to force a relayout or to force a repaint from within your JS code (not exactly what you were asking, but useful in some circumstances).

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

The DOM is essentially a big shared data structure. The browser constructs it when the page is parsed. Then loading scripts and various JS events have a chance to modify it.

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

If you suddenly had multiple JS threads with access to the DOM running concurrently, you'd have a really complicated problem. How would you synchronize access? You couldn't even write the most basic DOM operation that would involve finding a DOM object in the page and then modifying it because that wouldn't be an atomic operation. The DOM could get changed between the time you found the DOM object and when you made your modification. Instead, you'd probably have to acquire a lock on at least a sub-tree in the DOM preventing it from being changed by some other thread while you were manipulating or searching it. Then, after making the modifications, you'd have to release the lock and release any knowledge of the state of the DOM from your code (because as soon as you release the lock, some other thread could be changing it). And, if you didn't do things correctly, you could end up with deadlocks or all sorts of nasty bugs. In reality, you'd have to treat the DOM like a concurrent, multi-user datastore. This would be a significantly more complex programming model.

在单线程 JS"设计决策中有一个统一的主题.保持简单.无需了解多线程环境和线程同步工具,无需多线程调试即可编写可靠、可靠的浏览器 Javascript.

There is one unifying theme among the "single threaded JS" design decision. Keep things simple. Don't require an understanding of a multiple-threaded environment and thread synchronization tools and debugging of multiple threads in order to write solid, reliable browser Javascript.

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

One reason browser Javascript is a successful platform is because it is very accessible to all levels of developers and it relatively easy to learn and to write solid code. While browser JS may get more advanced features over time (like we got with WebWorkers), you can be absolutely sure that these will be done in a way that simple things stay simple while more advanced things can be done by more advanced developers, but without breaking any of the things that keep things simple now.

仅供参考,我已经在 node.js 中编写了一个多用户 Web 服务器应用程序,我经常惊讶于由于 nodejs Javascript 的单线程特性,服务器设计的复杂程度如此之低.是的,有一些东西写起来更痛苦(学习编写大量异步代码的承诺),但是哇,简化的假设你的 JS 代码永远不会被另一个请求中断,这大大简化了设计、测试并减少了很难发现和修复并发设计和编码总是充满的错误.

FYI, I've written a multi-user web server application in node.js and I am constantly amazed at how much less complicated much of the server design is because of single threaded nature of nodejs Javascript. Yes, there are a few things that are more of a pain to write (learn promises for writing lots of async code), but wow the simplifying assumption that your JS code is never interrupted by another request drastically simplifies the design, testing and reduces the hard to find and fix bugs that concurrency design and coding is always fraught with.

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

Certainly the first issue could be solved by allowing user action event handlers to run in their own thread so they could occur any time. But, then you immediately have multi-threaded Javascript and now require a whole new JS infrastructure for thread synchronization and whole new classes of bugs. The designers of browser Javascript have consistently decided not to open that box.

如果需要,可以改进渲染问题,但会使浏览器代码变得非常复杂.您必须发明某种方法来猜测正在运行的 JS 代码何时看起来不再更改 DOM(也许一些毫秒数过去了而没有更多更改),因为您必须避免立即进行重新布局和屏幕绘制每次 DOM 更改.如果浏览器这样做,某些 JS 操作将比现在慢 100 倍(100 倍是一个疯狂的猜测,但关键是它们会慢很多).而且,您必须在布局、绘制和 JS DOM 修改之间实现线程同步,这是可行的,但很复杂,需要大量工作,并且是浏览器实现错误的沃土.而且,您必须决定在重新布局或重绘中途并且 JS 线程进行 DOM 修改时该怎么做(没有一个答案很好).

The Rendering issue could be improved if desired, but at a significant complication to the browser code. You'd have to invent some way to guess when the running JS code seems like it is no longer changing the DOM (perhaps some number of ms go by with no more changes) because you have to avoid doing a relayout and screen paint immediately on every DOM change. If the browser did that, some JS operations would become 100x slower than they are today (the 100x is a wild guess, but the point is they'd be a lot slower). And, you'd have to implement thread synchronization between layout, painting and JS DOM modifications which is doable, but complicated, a lot of work and a fertile ground for browser implementation bugs. And, you have to decide what to do when you're part-way through a relayout or repaint and the JS thread makes a DOM modification (none of the answers are great).

这篇关于为什么 JavaScript 在普通浏览器中没有自己的线程?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆