【问题标题】:Does setTimeout or setInterval use thread to fire?setTimeout 或 setInterval 是否使用线程触发?
【发布时间】:2015-04-23 10:05:08
【问题描述】:

我一直在阅读这篇文章 http://ejohn.org/blog/how-javascript-timers-work/ 以及 setTimeoutsetInterval 以及其他异步任务(例如按钮单击)如何让我有些困惑。

我知道 JS 是单线程的,也就是说,AFAIK,所有的回调函数(也就是事件处理程序)都会被排队并按顺序执行。但是,请看下面我从文章中截取的图片,上面有链接:

每个块代表一些工作,并且 - 在大约 10 毫秒时 - 计时器被触发。我知道它的回调函数被放在队列中以供以后执行,但是为什么在已经执行某些东西的时候会调用事件呢?

是因为setTimeout() 开始使用单独的线程在内部计算时间并触发其完成事件吗?

请注意,我在这里不是在谈论它的回调执行;相反,我试图了解setTimeout 如何计算时间并触发其完成。我知道它的回调不会在其给定的时间参数之前被调用,但可能会更晚,但这是因为它的回调被排队到稍后的时间,当运行时找到一些时间来检查队列中是否有任何要执行的东西。

与这个问题类似,浏览器如何接受新的点击注册而 - 比方说 - 在用户点击的那一刻,一个循环在幕后工作?

如果你说浏览器为不同的事情维护不同的线程,那么我们可以在浏览器中调用JS单线程吗?

【问题讨论】:

标签: javascript multithreading


【解决方案1】:

不需要其他线程来解释这种行为。当一个计时器记录被添加到队列中时,它只是坐在那里。如果事件循环再次获得控制权,它只是检查是否有时间到的计划任务。

也不需要额外的线程来保持全局时间,因为这已经由操作系统或执行环境提供。

以这个简单的 PhantomJS 脚本为例:

function longRunningTask() {
    for(var i = 0; i < 100000; i++) {
        var s = "",
            s2 = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
        for(var j = 0; j < 1000; j++) {
            s += s2;
        }
    }
}

var start = new Date().getTime();
console.log("begin");
setTimeout(function(){
    console.log("end timer 1s " + (new Date().getTime() - start));
}, 1000);

setTimeout(function(){
    console.log("end timer 10s " + (new Date().getTime() - start));
}, 10000);
longRunningTask();
console.log("end longRunningTask " + (new Date().getTime() - start));

setTimeout(function(){
    console.log("EXIT");
    phantom.exit();
}, 11000);

产生以下输出:

开始 结束 longRunningTask 5025 结束计时器 1s 5029 结束计时器 10s 10001 出口

一秒定时器仅在控制权交还给事件循环时触发。

【讨论】:

    【解决方案2】:

    目前(Ecmascript 6),您永远不必担心函数内部的状态变化。

    然而,许多事情确实在后台运行,它们会改变自己的隔离环境,这些环境随后可能会作为数据块发送到主环境。 XMLHttpRequest 回调队列、计时器和网络工作者都这样做。它们都可能同时运行(在多个 CPU 中),但它们都以顺序方式与主环境通信。

    【讨论】:

      【解决方案3】:

      JavaScript 是单线程的,这意味着两段 JavaScript 不会同时执行(除非使用 worker,但每个 worker 也是单线程的)。但是当涉及到环境的 API 时,JavaScript 并不是唯一起作用的东西。像 setTimeoutsetIntervaladdEventListener 这样的函数是本地实现的(或者,至少在单线程 JavaScript 之外),它们的回调由环境触发,例如浏览器。正是环境将这些回调放入队列,由单线程 JavaScript 引擎执行。这就是浏览器能够接受要触发的新点击事件的方式,即使它仍在执行一些其他 JavaScript 代码。这就是 JavaScript 被认为是事件驱动的原因。

      【讨论】:

      • 所以,在“我不知道我在做什么级别”(因为我不知道)上,浏览器正在跟踪其他一些环境“东西”?您能否详细说明“本地执行”或为我指出一些好读物的正确方向?我对这个东西很好奇。
      • @Thomas 不幸的是,我手边没有任何链接,但“本地实现”是指这些 API 由主机环境实现,而不是在单线程 JavaScript 中实现或执行,只是回调是。
      • 浏览器也不一定是多线程的;您可以使用非常标准的事件循环非常轻松地实现问题中显示的图像,无需线程。
      • 这不太正确。多段代码可以并且确实同时执行,但它们必须位于不同的 Web Worker 上。 (线程!)然而,Web 工作者必须以单线程方式相互通信并与主线程通信。
      • @Agamemnus 呃,技术问题。我已经对此添加了注释。
      猜你喜欢
      • 2012-02-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-14
      • 2016-12-06
      • 1970-01-01
      • 2011-05-02
      相关资源
      最近更新 更多