在浏览器中禁用JS时,setTimeout在Greasemonkey用户脚本中不起作用

时间:2010-07-28 17:42:13

标签: javascript greasemonkey settimeout

我正在开发一个项目,该项目要求我的用户脚本在页面上运行,而不会执行任何页面的JavaScript。也就是说,我们需要禁用JavaScript浏览。

当我尝试延迟脚本中的函数执行时,我遇到了一个问题。每当我调用window.setTimeout时,我传入的函数永远不会被执行。

我想也许这个函数实际上是在unsafeWindow而不是窗口上调用的。这有什么解决方法吗?

我应该提一下,当启用JavaScript并且我的脚本中的其他所有内容在没有启用JavaScript的情况下工作正常时,对setTimeout的调用工作正常。

感谢您的帮助!

3 个答案:

答案 0 :(得分:4)

尽管Greasemonkey JavaScript以提升的权限运行,正如Pointy所说,setTimeout函数被附加到页面的JavaScript空间 - 根据需要包装在一个闭包中。 (在正常操作中,Greasemonkey实例经常在任何计时器消失时,它已设置,触发。)

因此,如果禁用页面的主JavaScript,则计时器将永远不会运行。

可能的解决方法:

  • 使用GM_xmlhttpRequest作为粗略延迟。您可以设置一个故意绘制其响应的页面。所以代码如下:

    GM_xmlhttpRequest
    (
        {
            method: "GET",
            url:    "http://YourTestServer.com/DelayService.php?Seconds=2",
            onload: function (response) {YourDelayedFunctionHere (); }
        }
    );
    

    调用您设置的实用程序页面为您做延迟。

  • 使用NoScript禁用除主页之外的所有页面的JavaScript。例如,对于页面 YourSite.com/testpage.htm ,其中包含来自 * SpamGenerator.net 的脚本...允许来自 YourSite.com 的脚本,但阻止来自 SpamGenerator.net

答案 1 :(得分:2)

window引用仍然是页面的window,只是包装在沙箱包装器中。当你打电话给setTimeout时,你仍在设置要由页面运行的内容。我认为必须是这样的情况,当Javascript被禁用时,浏览器根本不会触发那些超时事件(或者只是忽略事件)。

答案 2 :(得分:0)

这可以像这样打补丁:

你可以对NoScript + setTimeout =失败

说NO

greasemonkey.js中:找到[injectScripts]:function .....添加我们的GM-api .....

添加此代码:

sandbox.setTimeOut = function (callback, timeout, p1,p2,p3/*....*/){
    var args = Array.prototype.slice.call(arguments,2);
    return  sandbox.window.setTimeout(function(){
        return callback.apply(sandbox, args);
    } ,timeout);
}

sandbox.setInterval = function (callback, timeout, p1,p2,p3/*....*/){
    var args = Array.prototype.slice.call(arguments,2);
    return sandbox.window.setInterval(function(){
        return callback.apply(sandbox, args);
    } ,timeout);
}

此代码工作正常,我从2010年5月开始使用它。

user.js中,您可以像这样测试:

setTimeout(alert,1000, 'i am happy');
var loopid = setInterval(alert, 1000, 'I am happy again');
setTimeout(clearInterval, 5000, loopid);

var j=300;
for(;~j;j--){ //running perfectly!
    setTimeout(alert, 1000+20*j, 'I am happy' )
}

解决方案2

sandbox.kk_setTimeout = function (func, timeout, repeat_type, p1,p2,p3/*....*/){
    var callback = { k100: sandbox };
    var args = Array.slice.call(arguments,3);

    // repeat_type:  0=once  1=repeatng, after fired stopped    2=always repeat
    if(repeat_type!=2){
        callback.notify = function (timer){ func.apply(this.k100,args); }
        var timerCC = Components.Constructor("@mozilla.org/timer;1", "nsITimer", 'initWithCallback');
        var R = repeat_type?1:0;
    } else {
        callback.observe = function (subject, topic, data) { func.call(this.k100); };
        var timerCC = Components.Constructor("@mozilla.org/timer;1", "nsITimer", 'init'); 
        var R = 2; 
    }
    return new timerCC(callback, timeout, R);
}

// now have to test it:

var test100 = kk_setTimeout(alert, 1000, 0, 'i am timer');  //running = setTimeout
var test100 = kk_setTimeout(alert, 1000, 2, 'i am timer');  //running = setInterval
test100.cancal() ;   //clear it by cancel() method

kk_setTimeout(alert, 1000+20*j, 2, 'i am happy' );
var j=300;
for(;~j;j--){
    kk_setTimeout(alert, 1000+20*j, 0, 'i am happy 2' );
}

//bug:
//this solution 2 running after about 3-8 times differently stop, why bug ? i don't know.
// you will fail to use many times(over 3-8 time) kk_timeout(); or using repeat_type = 2 after fired 3-8 times timeout
//or running total time max about 20-30 seconds stop 
//--- this maybe stop by option in about:config -- about [max javascript run time]

china-kkmove patched


编辑以添加...

对不起大家,

我忘记编写的代码仍有一些补丁:

sandbox.window = sandbox._proto_; // add this line also to the solution 1#

今天早上我才想到这个错误。