3

Can setInterval result in other scripts in the page blocking?

I'm working on a project to convert a Gmail related bookmarklet into a Google Chrome extension. The bookmarklet uses the gmail greasemonkey API to interact with the gmail page. The JavaScript object for the API is one of the last parts of the Gmail page to load and is loaded into the page via XMLHttpRequest. Since I need access to this object, and global JavaScript variables are hidden from extension content scripts, I inject a script into the gmail page that polls for the variable's definition and then accesses it. I'm doing the polling using the setInterval function. This works about 80% of the time. The rest of the time the polling function keeps polling until reaching a limit I set and the greasemonkey API object is never defined in the page.

Injected script sample:

    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);
4

2 回答 2

11

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

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

因此,只要您的setInterval()处理程序不会卡住并永远运行,它就不会阻止其他事情最终运行。它可能会稍微延迟它们,但它们仍然会在当前setInterval()线程完成后立即运行。

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

以下是有关 Javascript 事件系统如何工作的其他一些参考资料:

JavaScript 如何在后台处理 AJAX 响应?

对 Javascript 方法的调用是线程安全的还是同步的?

我需要关注异步 Javascript 的竞争条件吗?

于 2012-08-15T23:19:40.850 回答
4

setInterval 和 setTimeout 是“礼貌的”,因为它们不会在您认为它们会触发时触发——它们会在您指定的点之后线程被清除的任何时候触发。

因此,调度某事的行为不会阻止其他某事运行——它只是将自己设置为在当前队列的末尾或指定时间的末尾(以较长者为准)运行。

两个重要的警告:

第一个是 setTimeout/setInterval 具有特定于浏览器的最小值。通常,它们大约为 15 毫秒。因此,如果您每 1 毫秒请求一次,浏览器实际上会将它们安排为每个 browser_min_ms(不是真正的变量)分开。

第二个是使用 setInterval,如果回调中的脚本花费的时间比间隔时间长,您可能会遇到一个火车事故,浏览器将继续排队等待积压的间隔。

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


setInterval(doExpensiveOperation, 10);

坏时间+=1;

但是对于您的代码,您所做的事情本质上没有任何问题。就像我说的,setInterval 不会中止其他任何事情的发生,它只会将自己注入到下一个可用插槽中。

我可能会建议您将 setTimeout 用于通用的东西,但是您仍然可以很好地保持间隔的标签并保持间隔。

在代码的其他地方可能还有其他事情发生——无论是在 Google 的交付中,还是在您的收藏中。

于 2012-08-15T23:35:38.517 回答