JavaScript的setInterval会阻塞线程执行吗?

7 浏览
0 Comments

JavaScript的setInterval会阻塞线程执行吗?

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);  // 取消注册此函数的间隔执行。
            gmonkey.load('1.0', function (gmail) {
                self.gmail = gmail;
                if (callback) { callback(); }
            });
        }
        else {
            attemptCount ++;  
            console.log("Gmonkey尚未加载:" + attemptCount );
            if (attemptCount > 30) {
                console.log("在三十秒内无法在gmail页面中找到Gmonkey。中止");
                clearInterval(intervalId);  // 取消注册此函数的间隔执行。
            };
        }
    };
    var intervalId = setInterval(function(){attemptLoad(callback);}, 1000);

0
0 Comments

JavaScript是单线程的,除了我们这里不讨论的Web Workers。这意味着只要常规的JavaScript线程执行,你的setInterval()定时器就不会运行,直到常规的JavaScript线程执行完毕。

同样地,如果你的setInterval()处理程序正在执行,其他JavaScript事件处理程序也不会触发,直到你的setInterval()处理程序完成当前的调用。

因此,只要你的setInterval()处理程序不被卡住并一直运行,它就不会阻塞其他事物的运行。它可能会稍微延迟它们的运行,但它们将在当前的setInterval()线程完成后立即运行。

在内部,JavaScript引擎使用一个队列。当某个东西想要运行(比如事件处理程序或setInterval()回调)并且已经有东西在运行时,它会将一个事件插入队列中。当当前的JavaScript线程执行完毕时,JS引擎会检查事件队列,如果有东西存在,它会选择最旧的事件并调用它的事件处理程序。

以下是关于JavaScript事件系统工作原理的其他一些参考资料:

- JavaScript如何处理后台的AJAX响应?

- JavaScript方法的调用是否线程安全或同步?

- 在异步JavaScript中,我需要担心竞态条件吗?

谢谢。我明白了,在处理程序运行时其他脚本无法运行,但我期望处理程序的执行非常简短,然后控制权会被交还给其他需要运行的脚本/事件,直到1秒的时间间隔过去,处理程序再次被调用。我在这方面有什么遗漏吗?

- 这是正确的解释。如果你的定时器脚本只运行很短的时间(比如几毫秒),那么在1秒的时间间隔中,剩余的时间都可以用于其他所有事件处理程序或定时器的运行。

这一定是stackoverflow上关于setInterval()的最好解释。

0
0 Comments

JavaScript的setInterval和setTimeout是“礼貌”的,因为它们不会在你期望的时间触发,而是在线程空闲后的任何时间触发,即在你指定的时间点之后。

因此,调度某个操作不会阻止其他操作的执行,它只是在当前队列的末尾或指定的时间结束时设置自己运行。

有两个重要的注意事项:

第一个注意事项是setTimeout和setInterval有特定于浏览器的最小间隔。通常,它们的最小间隔约为15毫秒。因此,如果你每1毫秒请求一次操作,浏览器实际上会将它们安排在间隔为browser_min_ms的时间间隔内(browser_min_ms不是真实变量)。

第二个注意事项是,如果setInterval中的脚本执行时间超过间隔时间,就会遇到一个问题,浏览器将不断排队积压间隔操作。

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

BadTimes+=1;

但是对于你的代码,你所做的事情本质上没有问题。

正如我之前说的,setInterval不会中断其他操作的执行,它只会插入到下一个可用时间槽中。

我可能会建议你在一般情况下使用setTimeout,但你仍然很好地控制了间隔并使其间隔开。

可能在代码的其他地方,或者在Google的交付中,或者在你的集合中还有其他问题。

0