86

我一直在阅读HTML5中的网络工作者,但我知道JavaScript是单线程的。

那么网络工作者是如何进行多线程工作的呢?或者,如果不是真正的多线程,他们是如何模拟的?

0

7个答案7

重置为默认值
103

正如一些评论已经指出的那样,Workers实际上是多线程的。

以下几点可能有助于澄清您的想法:

  • JavaScript是一种语言,它不定义线程模型,也不一定是单线程的
  • 大多数浏览器在历史上都是单线程的(尽管变化很快:工业工程,,Firefox浏览器),大多数JavaScript实现都发生在浏览器中
  • Web Workers不是JavaScript的一部分,它们是可以通过JavaScript访问的浏览器功能
4
  • 13
    这就是我遗漏了区别的地方,这是浏览器规范,而不是JavaScript语言。 评论 2012年3月14日18:52
  • 9
    @JamesDrinkard我认为主要问题是DOM公司不容易实现多线程,JavaScript通常用于DOM操作。但DOM不是JavaScript。
    – 罗伯特
    评论 2012年3月14日18:54
  • 5
    @JamesDrinkard javascript仍然是单线程即使是网络工作者。Web工作者不会以任何以前没有的方式使javascript多线程化,请这样想:您实际上是在启动另一个单线程进程并与之通信,就像您可以在node.js中那样。浏览器中的javascript是单线程的,而worker中的java脚本是单线程,但它们可以通过一个瘦通道相互通信。 评论 2018年3月15日11:17
  • 这就是我的理解:浏览器使用一个线程(包含javascript代码)来呈现DOM并处理相关的事件循环(也可以包含javascripts代码来执行非DOM操作,例如添加两个数字),但我们可以使用worker,通过它,浏览器只能执行非DOM(javascript still)代码。然后,我们可以在两者之间同步数据(在此处插入多线程概念)。所以,改写“詹姆斯·德利卡德”,“浏览器以单线程javascript处理DOM”; 我们仍然可以使用其他javascript线程不要触摸DOM 评论 2018年10月30日6:36
25

有点晚了,但我只是问了自己同样的问题,我得出了以下答案:
浏览器中的Javascript始终是单线程的一个基本的结果是,对变量的“并发”访问(多线程编程的主要难题)实际上不是并发的;这是真的除了网络工作者,它们实际上在单独的线程中运行必须以某种明确的方式处理对变量的并发访问.

我不是一个JavaScript忍者,但我也确信浏览器中的JavaScript是作为一个单线程进程提供的,而没有太多关注它是否属实或这一信念背后的理由。
支持这种假设的一个简单事实是,当用JavaScript编程时不必关心对共享变量的并发访问。每个开发人员都会编写代码,就好像对变量的每个访问都是一致的一样,甚至没有考虑到这个问题。
换句话说,你不需要担心所谓的内存模型.

事实上,不需要考虑WebWorkers来涉及JavaScript中的并行处理。考虑一个(异步)AJAX请求。想想你在处理并发访问变量时是多么粗心大意:

var计数器=0;函数asyncAddCounter(){var xhttp=新的XMLHttpRequest();xhttp.onreadystatechange=函数(){if(this.readyState==4){计数器++;}};xhttp.open(“GET”,“/a/remote/resource”,true);xhttp.send();}asyncAddCounter();计数器++;

它的价值是什么柜台在流程结束时?它是2.不管它是“并发”读写的,它都不会导致1。这意味着访问柜台总是一致的。如果两个线程真正并发地访问值,它们都可以通过读取0都写了1最后。

在浏览器中,远程资源的实际数据提取对开发人员是隐藏的,其内部工作不在JavaScript API的范围内(浏览器让您根据JavaScript指令控制什么)。就开发者而言结果的网络请求由主线程处理。
简而言之请求不可见,但调用回调(通过自定义JavaScript代码处理结果)由主线程执行。
可能,如果不是网络工作者,术语“多线程”永远不会进入Javascript世界。

请求的执行和异步回调的调用实际上是通过使用事件循环,而不是多线程。这对于一些浏览器来说都是正确的,显然对于Node.js也是如此。以下是一些参考文献,在某些情况下有点过时,但我想现在仍然保留着主要思想。

这就是为什么JavaScript被称为事件驱动型但不是多线程的。
注意,JavaScript因此允许异步习语,但不是平行JavaScript代码的执行(webworkers外部)。术语异步just表示两条指令的结果可能会按加扰顺序处理。

至于WebWorkers,他们是让开发人员控制多线程进程的JavaScript API。
因此,它们提供了显式方法来处理对共享内存的并发访问(在不同线程中读取和写入值),这是通过以下方式实现的:

  • 通过结构化克隆将数据推送到web工作者(这意味着新线程读取数据):结构化克隆算法-Web API | MDN本质上没有“共享”变量,而是给新线程一个对象的新副本。
  • 您可以通过转移值的所有权将数据推送到web工作者:可传输-Web API | MDN这意味着只有一个线程可以在任何时候读取其值。
  • 至于web工作人员返回的结果(他们如何“写入”),主线程在收到提示时访问结果(例如使用指令thisWorker.onmessage=函数(e){console.log(“消息”+e.data+“从工作者那里收到的”);}). 我想这一定是通过通常的事件循环。
  • 主线程和web工作者访问一个真正共享的内存SharedArrayBuffer(共享阵列缓冲区),可以使用原子功能。我发现这一点在本文中得到了明确的揭示:JavaScript:从工作者到共享内存
  • 注意:网络工作者无法访问DOM,这是真正共享的!
1
  • 更好、完整和解释的答案,应该是公认的正确答案。
    – 乌鸦伤
    评论 2月14日14:54
10

您将.js文件派生为“worker”,它在单独的线程中运行进程。您可以在它和“主”线程之间来回传递JSON数据。不过,工作人员无法访问某些东西,比如DOM。

比如说,如果你想解决复杂的数学问题,你可以让用户在浏览器中输入内容,将这些变量传递给工作线程,让它在后台进行计算,而在主线程中,你可以允许用户做其他事情,或显示进度条或其他东西,然后当工作线程完成时,它传回答案,然后打印到页面上。您甚至可以异步处理多个问题,并在完成时按顺序返回答案。非常整洁!

1
2

实际上,我认为主要的困惑在于,人们正在寻找聪明的方法来同时做事情。如果你仔细想想,JavaScript显然不是多线程的,但我们有并行的方法,那么发生了什么?

提出正确的问题才是答案所在。谁负责线程?上面有一个答案,说JS只是一种语言,而不是线程模型。完全正确!JavaScript与此无关。责任落在V8上。查看此链接以了解更多信息->https://v8.dev网址/因此,V8允许每个JS Context有一个线程,这意味着,无论您多么努力,生成一个新线程都是不可能的。然而,人们产生了所谓的工人,我们感到困惑。为了回答这个问题,我问你以下几点。是否可以启动2V8,然后两者都解释一些JS代码?正是我们问题的解决方案。员工与消息沟通是因为他们的上下文不同。它们是其他对我们的上下文一无所知的东西,因此它们需要一些以消息形式出现的信息。

2

答案声称“JavaScript是一种语言,它没有定义线程模型,也不一定是单线程的”,这是直接从一篇媒体文章中复制出来的。。。而且它在没有解决疑问的情况下会产生混淆。

与所有其他语言一样,它不一定是单线程的。对。。。但是

Javascript是一种用于单线程编程的语言,这就是它的美妙之处,使它易于实现。它是围绕单个调用堆栈设计的。也许在未来,随着新的实现,它将成为一种多线程编程语言。。。但现在,呼呼。

NodeV8仍然是单线程的,但它通过在用C++编写的LIBUV上创建工作线程来实现多线程功能。

同样,即使Javascript不适用于多线程,也可以通过使用浏览器API实现有限的多线程。

每次您在浏览器上打开TAB时,它都会创建一个新线程,这个过程与web工作者相同。

它在内部工作,但不能访问任何窗口对象。

是的,人们可以称之为多线程,如果它能让他们快乐,但在2021年,答案是“JS用于单线程编程(或单线程语言),但使用浏览器API(如Web Workers)可以实现有限的多线程”

1

浏览器使用您想要执行的javascript启动线程。因此,这是一个真正的线程,有了这个web工人的东西,您的js不再是单线程的。

0

众所周知,JavaScript是单线程的:所有代码都按顺序排队和执行。

使用WebWorkers,我们可以并发运行JavaScript进程(或者至少在该语言允许的情况下尽可能接近并发运行)。这种方法的主要好处是在不干扰用户界面的情况下处理后台线程中的数据操作。

使用web worker:

WebWorkers允许您在网页上并行运行JavaScript,而不会阻塞用户界面。

  • Web工作者在单独的线程中执行
  • 需要将所有工作代码托管在单独的文件中
  • 它们不是自动垃圾收集的,所以您需要控制它们。
  • 要运行worker,请使用worker.postMessage(“”);
  • 要停止工作人员,调用程序代码有两种方法terminate()和close()来自Worker本身
  • 实例化一个工作者将花费一些内存。

Web Workers在独立线程中运行。因此,它们执行的代码需要包含在单独的文件中。但在我们这样做之前,首先要做的是在主页中创建一个新的Worker对象。构造函数使用辅助脚本的名称:

var-worker=新工人('task.js');

如果指定的文件存在,浏览器将生成一个新的工作线程,该线程将异步下载。直到文件完全下载并执行后,工作程序才会开始。如果指向工人的路径返回404,工人将自动失败。

创建worker后,通过调用postMessage()方法启动它:

worker.postMessage();//启动工人。

通过消息传递与工人通信

作品与其父页面之间的通信是使用事件模型和postMessage()方法完成的。根据您的浏览器/版本,postMessage()可以接受字符串或JSON对象作为其单个参数。最新版本的现代浏览器支持传递JSON对象。

下面是一个使用字符串将“Hello World”传递给doWork.js中的工人的示例。工作者只需返回传递给它的消息。

主要脚本:

var worker=新工人('doWork.js');worker.addEventListener(“消息”,函数(e){console.log('工人说:',e.data);},假);worker.postMessage(“你好,世界”);//将数据发送给我们的员工。

doWork.js(工人):

self.addEventListener(“消息”,函数(e){self.postMessage(e.data);//将数据发送回主脚本},错误);

当从主页调用postMessage()时,我们的工作人员通过为消息事件定义一个onmessage处理程序来处理该消息。消息有效载荷(在本例中为“Hello World”)可在Event.data中访问。此示例演示了postMessage()也是将数据传递回主线程的方法。方便!

参考文献:

http://www.tothenew.com/blog/multi-threading-in-javascript-using-web-workers/

https://www.html5rocks.com/en/tutorials/workers/basics网站/

https://dzone.com/articles/easily-parallelize-jobs-using-0

2
  • 你参考资料部分的第一个链接已经失效。
    – 泰勒H
    评论 2022年7月12日16:28
  • 谢谢分享。但这仍然不能回答主线程的问题。您提到了“Web工作者在单独的线程中执行”,但由于javascript在单个线程中运行,那么这个“单独的线程”在哪里出现? 评论 2023年10月23日2:49

你的答案

单击“发布您的答案”,表示您同意我们的服务条款并确认您已阅读我们的隐私政策.

不是你想要的答案吗?浏览标记的其他问题问你自己的问题.