312

这是一个深思熟虑的设计决定,还是我们当前浏览器的问题,这些问题将在未来的版本中得到纠正?

4

16 回答 16

225

JavaScript 不支持多线程,因为浏览器中的 JavaScript 解释器是单线程 (AFAIK)。即使是谷歌浏览器也不会让单个网页的 JavaScript 并发运行,因为这会导致现有网页出现大量并发问题。Chrome 所做的只是将多个组件(不同的选项卡、插件等)分离到单独的进程中,但我无法想象一个页面有多个 JavaScript 线程。

但是,正如建议的那样,您可以使用setTimeout来允许某种调度和“假”并发。这会导致浏览器重新获得对渲染线程的控制权,并setTimeout在给定的毫秒数后启动提供给的 JavaScript 代码。如果您希望在对其执行操作时允许刷新视口(您所看到的),这将非常有用。只需循环例如坐标并相应地更新元素只会让您看到开始和结束位置,而在两者之间什么都没有。

我们在 JavaScript 中使用了一个抽象库,它允许我们创建由同一个 JavaScript 解释器管理的进程和线程。这允许我们以以下方式运行操作:

  • 进程 A,线程 1
  • 进程 A,线程 2
  • 进程 B,线程 1
  • 进程 A,线程 3
  • 进程 A,线程 4
  • 进程 B,线程 2
  • 暂停过程 A
  • 进程 B,线程 3
  • 进程 B,线程 4
  • 进程 B,线程 5
  • 启动过程 A
  • 进程 A,线程 5

这允许某种形式的调度和伪造并行性、线程的启动和停止等,但它不会是真正的多线程。我认为它永远不会在语言本身中实现,因为真正的多线程只有在浏览器可以运行单页多线程(甚至多个内核)时才有用,而且困难更大比额外的可能性。

对于 JavaScript 的未来,请查看: https ://developer.mozilla.org/presentations/xtech2006/javascript/

于 2008-09-02T16:29:36.627 回答
30

JavaScript 多线程(有一些限制)就在这里。Google 为 Gears 实现了 worker,并且 worker 被包含在 HTML5 中。大多数浏览器已经添加了对此功能的支持。

数据的线程安全得到保证,因为与工作人员通信的所有数据都是序列化/复制的。

有关更多信息,请阅读:

http://www.whatwg.org/specs/web-workers/current-work/

http://ejohn.org/blog/web-workers/

于 2010-04-30T18:37:20.853 回答
25

传统上,JS 旨在编写简短、快速运行的代码。如果你有主要的计算,你在服务器上做 - 一个 JS+HTML应用程序在你的浏览器中运行很长时间来做不平凡的事情的想法是荒谬的。

当然,现在我们有了。但是,浏览器需要一点时间才能赶上——它们中的大多数都是围绕单线程模型设计的,改变这一点并不容易。Google Gears 通过要求隔离后台执行来回避许多潜在问题 - 不更改 DOM(因为这不是线程安全的),不访问由主线程创建的对象(同上)。虽然具有限制性,但在不久的将来,这可能是最实用的设计,既因为它简化了浏览器的设计,又因为它降低了让没有经验的 JS 编码人员乱搞线程所涉及的风险……

@marcio

为什么这是不在 Javascript 中实现多线程的原因?程序员可以使用他们拥有的工具做任何他们想做的事情。

因此,我们不要给他们提供容易被滥用的工具,以至于我打开的每个其他网站最终都会导致我的浏览器崩溃。一个幼稚的实现会让你直接进入在 IE7 开发过程中给 MS 带来很多麻烦的领域:附加组件作者在线程模型上玩得又快又松,导致隐藏的错误在主线程上的对象生命周期发生变化时变得明显. 坏的。如果您正在为 IE 编写多线程 ActiveX 附加组件,我猜它是与领域相关的;并不意味着它需要走得更远。

于 2008-09-02T16:19:46.603 回答
13

我不知道这个决定的基本原理,但我知道您可以使用 setTimeout 模拟多线程编程的一些好处。您可以产生多个进程同时做事的错觉,但实际上,一切都发生在一个线程中。

只需让您的函数做一些工作,然后调用类似:

setTimeout(function () {
    ... do the rest of the work...
}, 0);

当他们有机会时,任何其他需要做的事情(如 UI 更新、动画图像等)都会发生。

于 2008-09-02T16:16:13.367 回答
11

您的意思是为什么该语言不支持多线程,或者为什么浏览器中的 JavaScript 引擎不支持多线程?

第一个问题的答案是,浏览器中的 JavaScript 旨在以独立于机器/操作系统的方式在沙箱中运行,添加多线程支持会使语言复杂化并使语言与操作系统过于紧密地联系在一起。

于 2008-09-02T16:09:40.293 回答
9

Node.js 10.5+ 支持工作线程作为实验功能(您可以在启用--experimental-worker标志的情况下使用它): https ://nodejs.org/api/worker_threads.html

所以,规则是:

  • 如果您需要执行I/O 绑定操作,请使用内部机制(也称为回调/承诺/异步等待)
  • 如果您需要执行CPU 绑定操作,请使用工作线程。

工作线程旨在成为长期存在的线程,这意味着您生成一个后台线程,然后通过消息传递与它进行通信。

否则,如果您需要使用匿名函数执行繁重的 CPU 负载,那么您可以使用https://github.com/wilk/microjob,这是一个围绕工作线程构建的小型库。

于 2018-09-06T13:52:57.987 回答
6

正如matt b所说,这个问题不是很清楚。假设您要询问语言中的多线程支持:因为当前在浏览器中运行的 99.999% 的应用程序不需要它。如果你真的需要它,有一些变通方法(比如使用 window.setTimeout)。

一般来说,多线程非常、非常、非常、非常、非常、非常困难(我说这很难吗?),除非你施加额外的限制(比如只使用不可变数据)。

于 2008-09-02T16:24:01.710 回答
3

英特尔一直在对 Javascript 中的多线程进行一些开源研究,最近在 GDC 2012 上进行了展示。这是视频的链接。该研究小组使用了主要关注英特尔芯片组和 Windows 操作系统的 OpenCL。该项目代号为 RiverTrail,代码可在 GitHub 上获取

一些更有用的链接:

为 Web 应用程序构建计算高速公路

于 2012-04-01T20:24:06.860 回答
2

目前一些浏览器确实支持多线程。因此,如果您需要,您可以使用特定的库。例如,查看下一个材料:

于 2015-12-07T12:38:16.593 回答
2

Javascript 是一种单线程语言。这意味着它有一个调用栈和一个内存堆。正如预期的那样,它按顺序执行代码,并且必须在执行下一段代码之前完成一段代码。它是同步的,但有时可能是有害的。例如,如果一个函数需要一段时间才能执行或必须等待某事,它会同时冻结所有内容。

于 2020-01-21T15:02:26.137 回答
1

它是不支持多线程的实现。目前,Google Gears 正在提供一种通过执行外部进程来使用某种形式的并发性的方法,仅此而已。

谷歌今天应该发布的新浏览器(谷歌浏览器)通过在进程中分离一些代码来并行执行一些代码。

核心语言当然可以具有与 Java 相同的支持,但对 Erlang 的并发性之类的支持还远远不够。

于 2008-09-02T16:14:48.083 回答
0

据我所知,谷歌浏览器会有多线程 javascript,所以这是一个“当前实现”的问题。

于 2008-09-02T16:05:38.557 回答
0

如果没有对线程同步的适当语言支持,尝试新的实现甚至没有意义。现有的复杂 JS 应用程序(例如任何使用 ExtJS 的应用程序)很可能会意外崩溃,但如果没有synchronized关键字或类似的东西,编写行为正确的新程序也将非常困难甚至不可能。

于 2010-03-08T08:54:47.403 回答
0

实际上多线程与语言本身无关。这是一个用于 .NET 的多线程 Javascript 引擎。它适用于多线程场景。它与 C# 运行时集成,因此所有同步逻辑都类似于 C#。您可以启动/等待/等待任务,也可以启动线程。你甚至可以放锁。以下示例演示了在 .NET 运行时中使用 Javascript 语法的并行循环。

https://github.com/koculu/topaz

var engine = new TopazEngine();
engine.AddType(typeof(Console), "Console");
topazEngine.AddType(typeof(Parallel), "Parallel");
engine.ExecuteScript(@"
var sharedVariable = 0
function f1(i) {
    sharedVariable = i
}
Parallel.For(0, 100000 , f1)
Console.WriteLine(`Final value: {sharedVariable}`);
");

除此之外,微软正在开发 Napa.js,这是一个支持多线程的 Node.js 克隆。

https://github.com/microsoft/napajs

于 2021-10-31T06:09:09.017 回答
-2

但是,您可以使用 eval 函数在一定程度上实现并发

/* content of the threads to be run */
var threads = [
        [
            "document.write('Foo <br/>');",
            "document.write('Foo <br/>');",
            "document.write('Foo <br/>');",
            "document.write('Foo <br/>');",
            "document.write('Foo <br/>');",
            "document.write('Foo <br/>');",
            "document.write('Foo <br/>');",
            "document.write('Foo <br/>');",
            "document.write('Foo <br/>');",
            "document.write('Foo <br/>');"
        ],
        [
            "document.write('Bar <br/>');",
            "document.write('Bar <br/>');",
            "document.write('Bar <br/>');",
            "document.write('Bar <br/>');",
            "document.write('Bar <br/>');",
            "document.write('Bar <br/>');",
            "document.write('Bar <br/>');",
            "document.write('Bar <br/>');",
            "document.write('Bar <br/>');"
        ]
    ];

window.onload = function() {
    var lines = 0, quantum = 3, max = 0;

    /* get the longer thread length */
    for(var i=0; i<threads.length; i++) {
        if(max < threads[i].length) {
            max = threads[i].length;
        }
    }

    /* execute them */
    while(lines < max) {
        for(var i=0; i<threads.length; i++) {
            for(var j = lines; j < threads[i].length && j < (lines + quantum); j++) {
                eval(threads[i][j]);
            }
        }
        lines += quantum;
    }
}
于 2017-02-11T05:53:01.343 回答
-3

使用 HTML5 带来的 webworkers 显然可以使用 javascript 进行多线程。

webworkers 和标准多线程环境之间的主要区别是内存资源不与主线程共享,对对象的引用从一个线程到另一个线程不可见。线程通过交换消息进行通信,因此可以按照事件驱动的设计模式实现同步和并发方法调用算法。

存在许多允许在线程之间构建编程的框架,其中包括 OODK-JS,一个支持并发编程的 OOP js 框架 https://github.com/GOMServices/oodk-js-oop-for-js

于 2016-09-11T13:47:46.337 回答