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

2024-04-07

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

这是为什么?

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

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


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

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

渲染

渲染比较复杂。典型的 DOM 修改顺序是这样的:1) DOM 被 JS 修改,布局标记为脏,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(也许经过了一些毫秒而没有更多更改),因为你必须避免立即进行重新布局和屏幕绘制每次 DOM 更改。如果浏览器这样做,一些 JS 操作将比现在慢 100 倍(100 倍是一个疯狂的猜测,但重点是它们会慢很多)。而且,您必须在布局、绘制和 JS DOM 修改之间实现线程同步,这是可行的,但很复杂,需要大量工作,并且为浏览器实现错误提供了肥沃的土壤。而且,您必须决定当您在重新布局或重绘过程中并且 JS 线程进行 DOM 修改时要做什么(没有一个答案很好)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么 JavaScript 在普通浏览器中没有自己的线程? 的相关文章

  • 类似于 iPhone(老虎机)的网络“选择器”选择框? [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我正在寻找一个类似 iPhone 的 选择器 控件 我可以在网络上使用它 可访问性不是问题 JavaS
  • JavaScript 为什么操作 __proto__ 很慢? [复制]

    这个问题在这里已经有答案了 与此线程相关 JavaScript 修改函数原型的更好方法 https stackoverflow com questions 21788187 javascript better way to modify f
  • 尝试旋转和变换 SVG 路径 - 我需要三角学计算吗?

    我正在尝试使用鼠标 SVG 路径进行操作 该路径代表电子电阻器的符号 该符号需要使用 引线 末端进行操作 如果您可以想象真实的电阻器 因此 我试图实现拖动第一个点周围 第二个点仍然存在 并且当在新坐标上拖动第一个点时 路径的所有点都按比例表
  • 使用 Javascript 防止刷新“跳转”

    我注意到 如果您在一个页面上并且向下滚动了很多 如果您刷新页面 大多数浏览器会将您跳回到您的位置 有什么办法可以防止这种情况发生吗 我研究了两个选项 但在 Webkit Firefox 上都不一致 window scrollTo 0 1 h
  • 如何使用 Fabric js 以编程方式自由绘制?

    使用 Fabric js 构建多人涂鸦 尝试使用 Fabric js 实现多人涂鸦 想法是当 U1 在画布上绘制时 我们将点推送到 RTDB 并在客户端上获取这些点 并以编程方式在两个客户端中绘制笔画 您可以将画布的数据保存在path cr
  • 重新加载页面时保持计时器(setInterval)运行

    加载网页后 我会通过控制台插入一些 Javscript 我想知道我是否可以使用 Javascript 或 jQuery 重新加载页面 不是从缓存 同时保留我正在运行的 setInterval 我熟悉 location reload 但这会终
  • 表单验证后 isValid 保持 false

    我有一个自定义验证函数 但即使它没有返回错误 表单仍然无效 我将以下属性传递给 Formik validate import files gt return import files values length 0 import files
  • 保护客户端 API 的安全

    我正在为基于 JavaScript 的游戏构建服务器端 API 和客户端库 其中必须确保两个非常重要的功能的安全 用户每次游玩都必须扣款 我们必须确保提交的分数是玩家实际获得的分数 解决第一个问题看起来很简单 在每次游戏开始时 我们都会调用
  • 计算链接上的点击次数(不带 onclick)[关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 我有诸如此类的链接 a href h
  • 将数组传递给 include() javascript

    我试图找出一个字符串是否包含存储在数组中的多个字符串 includes 所以我尝试过 let string hello james console log string includes hello james 但它被返回为false 当我
  • onchange 选择框

    假设我们有 2 个不同的选择框 具有相同数量的选项
  • 如何将对象传递给 onclick 事件[重复]

    这个问题在这里已经有答案了 可能的重复 Javascript 循环内的事件处理程序 需要闭包吗 https stackoverflow com questions 341723 event handlers inside a javascr
  • JavaScript 从 json 迭代键和值? [复制]

    这个问题在这里已经有答案了 我正在尝试迭代以下 json VERSION 2006 10 27 a JOBNAME EXEC JOBHOST Test LSFQUEUE 45 LSFLIMIT 2006 10 27 NEWUSER 3 NE
  • Html页面在底部加载

    我需要一个 HTML 页面在页面加载时自动向下滚动 所以基本上加载在底部 可以使用JavaScipt吗 请您帮助我或引导我走向正确的方向 感谢所有帮助 谢谢 尝试这个 window scroll 0 document documentEle
  • 根据用户投票移动 div

    我是新来的 但我喜欢这个网站 我检查了其他类似的问题 但没有看到我要找的东西 我是一名音乐家 有一段时间我一直在做 每日之歌 每天写一首小歌 我想将歌曲发布为 div 在里面 li 在 div 中 我只想要一个简单的 mp3 播放器和一个
  • HTML Canvas:如何绘制翻转/镜像图像?

    当我在 HTML 画布上绘制图像时 我试图翻转 镜像图像 我发现一个游戏教程显示了角色必须面对的每个方向的精灵表 但这对我来说似乎不太正确 特别是因为每个框架都有不同的尺寸 实现这一目标的最佳技术是什么 我尝试致电setScale 1 1
  • 为什么 JavaScript 在不同浏览器中不一致?

    在花了无数个小时修复 JS 以使其跨浏览器兼容 主要是 IE 之后 我一直在思考以下问题 Why不是 JavaScript持续的跨浏览器 我的意思是 为什么 JS 不能像 Java 和 Flash 那样好呢 相反 我们必须求助于 jQuer
  • 如何以编程方式移动 OpenLayers Vector?

    API 文档为OpenLayers Feature Vector http dev openlayers org apidocs files OpenLayers Feature Vector js html说 Vector 本身根本没有方
  • 使用node和multer将图像上传到heroku不起作用

    我正在尝试使用 Node 后端将图像文件上传到 Heroku 我可以使其工作 同样的过程在本地主机测试中工作得很好 但是在将我的项目部署到 Heroku 并测试它之后 过程和文件中出现错误不会上传 后端 let storage multer
  • Firebug 分析问题:“没有要分析的活动”

    我想用一些 javascript jQuery 尝试一些不同的选项 看看哪个是最快的 但是我无法让分析正常工作 这是我要测试的代码 this keypress function e console profile test retrieve

随机推荐

  • 使用 REST API 将端口绑定到主机接口

    命令行界面的文档说明如下 将容器的端口绑定到主机的特定接口 系统 使用docker run命令的 p参数 一般语法 docker run p
  • 是否可以使用 Apache 记录所有 HTTP 请求标头?

    如何将 apache 收到的 HTTP 请求标头 全部 的内容记录到日志文件中 目前我的apache组合日志格式配置是 LogFormat h l u t r gt s b Referer i User Agent i Cookie i c
  • 使用 Jquery 的模态 PDF IFRAME

    这是我的脚本 运行完美 没有问题 现在为什么我将其发布在这里 主要是为了我可以增强它并使其变得更好 我也认为这可以帮助其他人 JQUERY 这是一个工作示例http jsfiddle net cornelas 4eUgf 2 http js
  • vim 中递归搜索模式的函数

    我有一个包含简单文本行的文本文件 我想创建一个函数vim and gvim 文本编辑器 can be sent a variable number of patterns and it should find lines will all
  • CDF 累积分布函数误差

    我正在尝试为多列数据文件中的一列绘制 CDF 当数据文件中仅存在一列时 它可以很好地绘制 当我尝试从数据中获取特定列时 它给了我错误 我还尝试使用 for 循环来读取它读起来很好的特定列 如果我在 for 循环之外给出绘图语句 则绘图仅显示
  • C++ 中字符串文字的类型是什么? [复制]

    这个问题在这里已经有答案了 例如 字符串文字 Hello 的类型是什么 const char 6 or const char 字符串文字的类型 Hello 是 6 的数组const char 普通字符串文字和 UTF 8 字符串文字也称为窄
  • 使用 URL 进行简单的 Swift 文件下载

    因此 我将 URL 作为字符串 在本例中为 JPG 但如果可能的话 希望有一个适用于任何文件类型的通用过程 并将文件路径作为字符串 用于保存文件 实现这一点的最快方法是什么 请记住 这是针对 OSX 命令行应用程序的 我尝试了这里找到的一些
  • 如何一键点击链接即可实现“链接另存为”功能? [复制]

    这个问题在这里已经有答案了 因此 正如你们大多数人可能知道的那样 当您在网页上放置文件的链接时 您必须右键单击该链接 然后单击 链接另存为 才能下载该文件 我想知道是否有一种方法可以单击链接并自动下载文件 有一个方法 使用header 调用
  • 在 C# 中追加两个或多个字节数组

    在 C 中是否有最好的 见下文 方法来附加两个字节数组 假装我拥有完全的控制权 我可以使第一个字节数组足够大以在末尾保存第二个字节数组并使用数组 复制到 https msdn microsoft com en us library syst
  • 当返回自定义对象列表时,RxJava 突出显示错误但编译

    我正在进行 RxJava 调用 我订阅的最终结果是预订列表 代码工作正常 但我得到了这个恼人的亮点 演员阵容在这里不起作用 因为我无法演员阵容List
  • 为什么 Linux 重定向会截断文件?

    我有一个名为 test txt 的文件 如下所示 hello world 它只是一个 hello world 字符串 如果我使用 perl 正则表达式 perl pe s hello bye g test txt it says bye w
  • 使用 itextsharp 使用数据库中的图像创建 pdf

    我有一个过程 其中 html 与图像链接存储在数据库中 图像也存储在数据库中 我创建了一个从数据库读取图像的控制器操作 我生成的路径是这样的 File Image path Root test jpg 该图像路径嵌入在 html 的 img
  • 使用自定义配置在调试模式下运行 sbt 项目

    我想使用特殊配置在我的 sbt 0 11 项目中引入调试模式 我尝试使用以下代码来实现这一点 但不幸的是 它似乎没有按预期工作 我正在启动debug run但运行并未按预期暂停 object Test extends Build lazy
  • 如何在 Windows 10 上解锁詹金斯

    我使用下载的 msi 在我的 Windows 10 机器上安装了 jenkins 它安装得很好 现在启动了浏览器 提示我使用初始管理员密码解锁詹金斯 我在任何地方都找不到这个文件 我查看了安装目录 C Program Files x86 J
  • 在 ControllerAdvice 之前捕获反序列化异常

    这是一个问题 我有一个采用输入模型的控制器 可以说 public class AppUserUpdateData NotNull Size min 1 max 50 protected String login JsonDeserializ
  • 处理 String.getBytes("UTF-8") 中的 UnsupportedEncodingException 的推荐方法

    建议的处理方式是什么不支持的编码异常 http docs oracle com javase 6 docs api java io UnsupportedEncodingException html在库方法中调用 String getByt
  • 如何更改 Paginator 的页面名称?

    Current Paginator正在使用 page N 但我想用别的东西 我怎样才能改变成这样 sida N反而 我看过Illuminate Pagination Environment并且有一个方法 setPageName 在那里改变它
  • 从浏览器调用 Android 应用程序

    我一直在尝试从浏览器调用我的应用程序安卓 3 1 蜂窝 这些是我尝试过的链接 但没有一个有效 a href click me 1 a a href click me 2 a a href click me 3 a 对于第一个和第二
  • 鼠标悬停/悬停效果在 IE8 上缓慢

    我注意到在 IE8 中 当在包含许多行 本例中为 100 行 的表上使用鼠标悬停事件时 性能会出现奇怪的情况 我尝试了很多不同的方法 但我似乎找不到任何方法来按照我喜欢 需要的速度获得它 如果我在每个事件上切换类 则所有 IE 版本的性能都
  • 为什么 JavaScript 在普通浏览器中没有自己的线程?

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