1

SetInterval是否可以阻塞页面中的其他脚本?JavaScript的setInterval块可以执行线程吗?

我正在开发一个项目,将Gmail相关书签转换为Google Chrome扩展程序。小书签使用gmail greasemonkey API与gmail页面进行交互。 API的JavaScript对象是要加载的Gmail页面的最后部分之一,并通过XMLHttpRequest加载到页面中。由于我需要访问此对象,并且全局JavaScript变量对扩展内容脚本隐藏,因此我在gmail页面中注入了一个脚本,用于轮询变量的定义,然后访问它。我正在使用setInterval函数进行轮询。这大约80%的时间工作。其余时间轮询功能保持轮询,直到达到我设置的限制,并且从未在页面中定义greasemonkey API对象。

注入脚本示例:

var attemptCount = 0; 

    var attemptLoad = function(callback) { 

     if (typeof(gmonkey) != "undefined"){ 
      clearInterval(intervalId); // unregister this function for interval execution. 
      gmonkey.load('1.0', function (gmail) { 
       self.gmail = gmail; 
       if (callback) { callback(); } 
      }); 
     } 
     else { 
      attemptCount ++; 
      console.log("Gmonkey not yet loaded: " + attemptCount); 
      if (attemptCount > 30) { 
       console.log("Could not fing Gmonkey in the gmail page after thirty seconds. Aborting"); 
       clearInterval(intervalId); // unregister this function for interval execution. 
      }; 
     } 
    }; 

    var intervalId = setInterval(function(){attemptLoad(callback);}, 1000); 
+1

那么,在执行回调期间,不能执行其他代码(事件处理程序,超时回调函数),因为JavaScript是单线程的......如果这就是你的意思。 – 2012-08-15 23:09:24

回答

10

JavaScript是单线程(除了我们不是在谈论这里网络工作者)。这意味着只要正常的JavaScript执行线程正在运行,您的setInterval()定时器将不会运行,直到执行正常的JavaScript线程完成。

同样,如果您的setInterval()处理程序正在执行,那么在您的setInterval()处理程序完成执行它的当前调用之前,不会触发其他JavaScript事件处理程序。

所以,只要您的setInterval()处理程序不会卡住并永久运行,它不会阻止其他事物最终运行。它可能会稍微延迟它们,但是只要当前的线程完成,它们仍然会运行。

在内部,JavaScript引擎使用一个队列。当某些事情想要运行时(如事件处理程序或setInterval()回调),并且某些事件已在运行时,它会将事件插入到队列中。当前的JavaScript线程完成执行时,JS引擎会检查事件队列,如果有事件发生,它将在那里选择最旧的事件并调用其事件处理程序。

这里是JavaScript的事件系统是如何工作的其他一些参考:

How does JavaScript handle AJAX responses in the background?

Are calls to Javascript methods thread-safe or synchronized?

Do I need to be concerned with race conditions with asynchronous Javascript?

+0

谢谢。我知道在处理程序运行时没有其他脚本可以运行,但是我的期望是处理程序的执行将非常简短,并且该控制权将被放弃到任何其他脚本/事件需要运行的时间,直到经过1秒的时间间隔并再次调用处理程序。有什么我失踪了吗? – 2012-08-15 23:31:02

+1

@BSharp - 这是正确的解释。如果您的计时器脚本只是短暂运行(如几毫秒),那么间隔计时器的1秒间隔内的所有其余时间可用于所有其他事件处理程序或计时器运行。 – jfriend00 2012-08-16 04:13:39

+0

这必须是关于stackoverflow的最好的setInterval()解释。 – Donato 2016-07-15 18:31:27

4

的setInterval和setTimeout的是 “礼貌”,因为他们不” t当你认为他们会 - 他们会在任何时候线程被清除时触发,在你指定的点后。因此,调度东西的行为不会阻止其它运行 - 它只是将自身设置为在当前队列的末尾运行,或者在指定时间结束时(以较长者为准)运行。

两个重要的注意事项:

首先将是的setTimeout/setInterval的具有特定浏览器的最小值。通常他们大约15ms。因此,如果你每1ms请求一次,浏览器实际上将它们安排为每个browser_min_ms(不是一个真正的变量)。

第二种情况是,如果回调中的脚本比间隔时间长,那么您可以运行到浏览器将继续排队积压间隔的列车故障。

function doExpensiveOperation() { 
    var i = 0, l = 20000000; 
    for (; i < l; i++) { 
     doDOMStuffTheWrongWay(i); 
    } 
} 


setInterval(doExpensiveOperation, 10); 

BadTimes + = 1;

但是,对于您的代码具体而言,没有什么本质上错误与你在做什么。 就像我说的,setInterval不会中止任何其他事情发生,它只会注入到下一个可用的插槽中。

我可能会推荐你使用setTimeout来作为通用的东西,但是你仍然在保持间隔标签并保持间隔的情况下做得很好。

代码中的其他地方可能还有其他事情正在进行,无论是在Google的投递中,还是在您的收藏中。

相关问题