在我的chrome扩展程序中,我在内容脚本中有一个setInterval,它会在每3秒后检查一次网页中的更改。
setInterval(detectChange, 3000)
function detectChange(){
...
}
这适用于除一个(www.rdio.com)之外的所有网站。网页脚本以某种方式清除通过内容脚本设置的间隔。
我想过将setInterval放在后台脚本中,并在每个时间间隔向内容脚本发送一条消息。但这需要我跟踪运行内容脚本的所有选项卡,这似乎不是一个好主意。
如果有办法,请告诉我。
答案 0 :(得分:2)
可取消的任务计划程序(setTimeout
,setInterval
,requestAnimationFrame
等)显然与文档相关联。虽然内容脚本的脚本执行上下文与页面隔离,但文档不是。
网站清除不是由网站本身创建的计时器似乎相当奇怪。您可以尝试调试问题,并通过覆盖clearTimeout
/ clearInterval
方法来检查网站清除计时器的原因。
这是一个捕获代码的示例,该代码清除脚本本身未安装的计时器:
// Run this content script at document_start
var s = document.createElement('script');
s.textContent = '(' + function() {
var clearTimeout = window.clearTimeout;
var setTimeout = window.setTimeout;
var setInterval = window.setInterval;
// NOTE: This list of handles is NEVER cleared, because it is the
// only way to keep track of the complete history of timers.
var handles = [];
window.setTimeout = function() {
var handle = setTimeout.apply(this, arguments);
if (handle) handles.push(handle);
return handle;
};
window.setInterval = function() {
var handle = setInterval.apply(this, arguments);
if (handle) handles.push(handle);
return handle;
};
window.clearTimeout = window.clearInterval = function(handle) {
clearTimeout(handle);
if (handle && handles.indexOf(handle) === -1) {
// Print a stack trace for debugging
console.trace('Cleared non-owned timer!');
// Or trigger a breakpoint so you can follow the call
// stack to identify which caller is responsible for
// clearing unknown timers.
debugger;
}
};
} + ')();';
(document.head || document.documentElement).appendChild(s);
s.remove();
如果这表明该网站有问题,并且(例如)清除每个偶数编号的计时器,那么您只需调用setTimeout两次即可解决问题。
例如:
Promise.race([
new Promise(function(resolve) {
setTimeout(resolve, 3000);
}),
new Promise(function(resolve) {
setTimeout(resolve, 3000);
});
}).then(function() {
// Any of the timers have fired
});
如果结果是网站以不可预测的方式清除计时器,您可以尝试使用其他异步方法或事件来计划任务,并测量调用之间的时间。经过一段时间后,只需触发回调即可。例如,使用requestAnimationFrame
(通常每秒多次):
function scheduleTask(callback, timeout) {
timeout = +timeout || 0;
var start = performance.now();
function onDone(timestamp) {
if (timestamp - start >= timeout) callback();
else requestAnimationFrame(onDone);
}
requestAnimationFrame(onDone);
}
// Usage example:
console.time('testScheduler');
scheduleTask(function() {
console.timeEnd('testScheduler');
}, 1000);
或插入<iframe>
并在框架的上下文中创建计时器。