setInterval结果可以阻止页面中的其他脚本吗?
我正在开展一个项目,将与Gmail相关的书签转换为Google Chrome扩展程序。 bookmarklet使用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);
答案 0 :(得分:10)
Javascript是单线程的(除了我们在这里没有讨论的网络工作者)。这意味着只要正常的javascript执行线程正在运行,你的setInterval()
计时器就不会运行,直到执行的常规javascript线程完成。
同样,如果您的setInterval()
处理程序正在执行,则在您的setInterval()
处理程序完成执行当前调用之前,不会触发其他javascript事件处理程序。
因此,只要您的setInterval()
处理程序不会卡住并永远运行,它就不会阻止其他事情最终运行。它可能会略微延迟它们,但它们仍会在当前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?
答案 1 :(得分:4)
setInterval和setTimeout是"礼貌",因为当你认为他们愿意时他们不会开火 - 他们会在线程清晰时触发, 之后你指定的点。
因此,安排某些事情的行为不会阻止其他东西运行 - 它只是将自己设置为在当前队列的末尾运行,或者在指定时间结束时运行(以较长者为准)
两个重要的警告:
第一个是setTimeout / setInterval具有特定于浏览器的最小值。他们经常在15ms左右。因此,如果您每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的投放中还是在您的收藏中。