【问题标题】:JavaScript and single-threadednessJavaScript 和单线程
【发布时间】:2011-11-01 23:33:35
【问题描述】:

我总是听说 JavaScript 是单线程的;当 JavaScript 被执行时,它都在同一个全局 mosh 坑中运行,都在一个线程中。

虽然这可能是真的,但单个执行线程可能会产生新线程,将数据异步返回到主线程,对吗?例如,当发送一个 XMLHttpRequest 时,浏览器不是创建一个执行 HTTP 事务的新线程,然后在 XMLHttpRequest 返回时在主线程中调用回调吗?

定时器——setTimeout 和 setInterval 呢?这些是如何工作的?

这种单线程是语言的结果吗?是什么阻止了 JavaScript 在新的 Web Workers 草案之前进行多线程执行?

【问题讨论】:

  • javaScript 解释器经常共享浏览器 UI 线程
  • 下次我说全局作用域时,我会用global mosh pit这个词:)

标签: javascript multithreading


【解决方案1】:

XMLHttpRequest,值得注意的是,不会阻塞当前线程。但是,它在运行时中的细节没有在任何规范中概述。它可以在单独的线程中运行,也可以在当前线程中运行,使用非阻塞 I/O。

setTimeoutsetInterval 设置计时器,当运行到零时,将执行项目(函数/回调的一行代码)添加到执行堆栈,如果代码执行已启动 JavaScript 引擎停了下来。换句话说,它们告诉 JavaScript 引擎在它完成当前正在做的事情之后再做一些事情。要查看实际情况,请在一个方法中设置多个 setTimeout(s) 并调用它。

【讨论】:

    【解决方案2】:

    您的 JavaScript 本身是单线程的。但是,它可能会与浏览器中的其他线程交互(通常用 C 和 C++ 之类的东西编写)。这就是异步 XHR 的工作方式。浏览器可能会创建一个新线程(或者它可能会通过事件循环重新使用现有线程。)

    定时器和间隔会尝试让你的 JavaScript 稍后运行,但如果你有一个 while(1){ ; } 正在运行,不要指望定时器或间隔会中断它。

    (编辑:遗漏了一些东西。) 单线程很大程度上是 ECMA 规范的结果。实际上没有用于处理多线程的语言结构。编写一个具有多个线程的 JavaScript 解释器以及与之交互的工具并非不可能,但没有人真正做到这一点。当然没有人会在网络浏览器中这样做。它会搞砸一切。 (如果你在做一些像 Node.js 这样的服务器端的事情,你会发现他们已经避开了 JavaScript 中的多线程,转而支持时髦的事件循环和可选的多处理。)

    【讨论】:

      【解决方案3】:

      请参阅this post,了解有关 javascript 事件队列如何工作的说明,包括它与 ajax 调用的关系。

      浏览器肯定使用至少一个本机操作系统线程/进程来处理操作系统的实际接口以检索系统事件(鼠标、键盘、计时器、网络事件等...)。是否存在多个本机操作系统级线程取决于浏览器的实现,并且与 Javascript 行为并不真正相关。来自外部世界的所有事件都经过 javascript 事件队列,并且在前一个执行的 javascript 线程完成之前不会处理任何事件,然后将下一个事件从提供给 javascript 引擎的队列中拉出。

      【讨论】:

        【解决方案4】:

        浏览器可能有其他线程来完成这项工作,但您的 Javascript 代码仍将在一个线程中执行。以下是它在实践中的工作方式。

        在超时的情况下,浏览器会创建一个单独的线程来等待超时到期或使用其他一些机制来实现实际的计时逻辑。然后超时到期,消息将被放置在主事件队列中,告诉运行时执行您的处理程序。一旦主线程接收到消息,这就会发生。

        AJAX 请求的工作方式类似。一些浏览器内部线程实际上可能会连接到服务器并等待响应,一旦响应可用,就会在主事件队列中放置适当的消息,以便主线程执行处理程序。

        在所有情况下,您的代码都将由主线程执行。这与大多数其他 UI 系统没有什么不同,只是浏览器对您隐藏了该逻辑。在其他平台上,您可能需要处理单独的线程并确保在 UI 线程上执行处理程序。

        【讨论】:

          【解决方案5】:

          说得比线程方面更简单,一般来说(对于我所知道的浏览器)在任何给定时间只会执行一个 JavaScript 块。

          当您发出异步 Ajax 请求或调用 setTimeoutsetInterval 时,浏览器可能会在另一个线程中管理它们,但回调中的实际 JS 代码要等到之后的某个时间点才会执行当前执行的代码块完成。它只是排队。

          证明这一点的一个简单测试是,如果您在 setTimeout 之后但在同一块中放置一段运行时间相对较长的代码:

          setTimeout("alert('Timeout!');", 5);
          alert("After setTimeout; before loop");    
          for (var i=0, x=0; i < 2000000; i++) { x += i };
          alert("After loop");
          

          如果您运行上述程序,您将看到“After setTimeout”警报,然后在循环运行时会暂停,然后您会看到“After loop”,然后您才会看到“Timeout !” - 即使显然已经超过 5 毫秒(特别是如果您需要一段时间来关闭第一个警报)。

          单线程的一个经常被引用的原因是它简化了浏览器渲染页面的工作,因为你不会遇到许多不同的 JavaScript 线程都试图同时更新 DOM 的情况.

          【讨论】:

            【解决方案6】:

            Javascript 是一种旨在嵌入的语言。它可以并且已经用于在不同操作线程上同时执行 javascript 的程序中。对嵌入式语言没有太多需求来显式控制新执行线程的创建,但它当然可以通过提供具有所需功能的宿主对象来完成。 WHATWG 实际上是includes a justification for their decision not to push a standard concurrent execution capability for browsers

            【讨论】:

              猜你喜欢
              • 2018-12-03
              • 2010-09-06
              • 1970-01-01
              • 2016-07-22
              • 2016-05-23
              • 2014-03-10
              • 1970-01-01
              • 2020-09-19
              相关资源
              最近更新 更多