JavaScript的setInterval可以阻止线程执行吗?

Can JavaScript's setInterval block thread execution?

本文关键字:线程 执行 setInterval JavaScript      更新时间:2023-09-26

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

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

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

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

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

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

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

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

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

setInterval和setTimeout是"礼貌的",因为它们不会在你认为它们会触发的时候触发 - 它们会在线程清除时触发,在你指定的点之后

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

两个重要的警告:

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

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

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

setInterval(doExpensiveOperation, 10);

坏时代+=1;

但特别是对于你的代码,你正在做的事情本身并没有什么问题。就像我说的,setInterval 不会中止任何其他事情的发生,它只会将自己注入下一个可用的插槽中。

我可能会建议你使用 setTimeout,用于通用的东西,但你仍然做得很好,保持间隔的标签并保持间隔。

代码中的其他地方可能还有其他事情发生 - 要么在Google的交付中,要么在您的集合中。