通过内容脚本设置的间隔被网页清除
Interval set through content script being cleared by webpage
在我的 chrome 扩展程序中,我在内容脚本中有一个 setInterval,它每 3 秒检查一次网页更改。
setInterval(detectChange, 3000)
function detectChange(){
...
}
除了一个 (www.rdio.com) 之外,这对所有网站都非常有效。网页脚本以某种方式清除了通过内容脚本设置的间隔。
我想到将 setInterval 放在后台脚本中,并在每个时间间隔向内容脚本发送一条消息。但这需要我跟踪内容脚本为 运行 的所有选项卡,这似乎不是一个好主意。
如果有办法请告诉我。
可取消任务调度程序(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>
并在框架的上下文中创建计时器。
在我的 chrome 扩展程序中,我在内容脚本中有一个 setInterval,它每 3 秒检查一次网页更改。
setInterval(detectChange, 3000)
function detectChange(){
...
}
除了一个 (www.rdio.com) 之外,这对所有网站都非常有效。网页脚本以某种方式清除了通过内容脚本设置的间隔。
我想到将 setInterval 放在后台脚本中,并在每个时间间隔向内容脚本发送一条消息。但这需要我跟踪内容脚本为 运行 的所有选项卡,这似乎不是一个好主意。
如果有办法请告诉我。
可取消任务调度程序(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>
并在框架的上下文中创建计时器。