通过网页清除内容脚本设置的间隔

时间:2015-02-14 13:49:15

标签: javascript google-chrome-extension

在我的chrome扩展程序中,我在内容脚本中有一个setInterval,它会在每3秒后检查一次网页中的更改。

setInterval(detectChange, 3000)

function detectChange(){
    ...
}

这适用于除一个(www.rdio.com)之外的所有网站。网页脚本以某种方式清除通过内容脚本设置的间隔。

我想过将setInterval放在后台脚本中,并在每个时间间隔向内容脚本发送一条消息。但这需要我跟踪运行内容脚本的所有选项卡,这似乎不是一个好主意。

如果有办法,请告诉我。

1 个答案:

答案 0 :(得分:2)

可取消的任务计划程序(setTimeoutsetIntervalrequestAnimationFrame等)显然与文档相关联。虽然内容脚本的脚本执行上下文与页面隔离,但文档不是。

网站清除不是由网站本身创建的计时器似乎相当奇怪。您可以尝试调试问题,并通过覆盖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>并在框架的上下文中创建计时器。