setTimeout not working in Greasemonkey user script when JS disabled in browser

我是研究僧i 提交于 2019-12-21 04:46:08

问题


I'm working on a project that requires my user script be run on pages as they are rendered without executing any of the page's JavaScript. That is to say, we need to browse with JavaScript disabled.

I've encountered a problem though when I try to delay execution of a function within my script. Whenever I make a call to window.setTimeout, the function I pass in never gets executed.

I think maybe this function is actually getting called on unsafeWindow instead of window. Is there any workaround for this?

I should mention that calls to setTimeout work fine when JavaScript is enabled and everything else in my script is working fine without enabling JavaScript.

Thanks for your help!


回答1:


Even though Greasemonkey JavaScript runs with elevated privileges, as Pointy said, setTimeout functions are appended to the page's JavaScript space -- wrapped in a closure as needed. (In normal operation, the Greasemonkey instance is often gone by the time any timers, it has set, fire.)

So, if the page's main JavaScript is disabled, the timer will never run.

Possible workarounds:

  • Use GM_xmlhttpRequest as a crude delay. You can setup a page that deliberately draws out its response. So code like:

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

    Would call a utility page that you set up to do the delay for you.

  • Use NoScript to disable all of the page's JavaScript except for the main page. For example, for page, YourSite.com/testpage.htm, which includes scripts from, say, *SpamGenerator.net... Allow scripts from YourSite.com but block them from SpamGenerator.net.




回答2:


The window reference is still the page's window, just wrapped in the sandbox wrapper thing. When you call setTimeout on it you're still setting up something to be run by the page. I suppose that it must be the case that the browser won't fire those timeout events at all (or will just ignore the events) when Javascript is disabled.




回答3:


this can be patched like this:

You can say NO to NoScript + setTimeout = failed

In greasemonkey.js: find [ injectScripts ]: function..... add our GM-api.....

Add this code:

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);
}

or

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);
}

This code is working fine, I have used it since May 2010.

In user.js you can test it like this:

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' )
}

Solution 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


edit to add…

Sorry everyone,

There are still a few patches to the code that I forgot to write:

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

This error just came to my mind this morning.



来源:https://stackoverflow.com/questions/3355735/settimeout-not-working-in-greasemonkey-user-script-when-js-disabled-in-browser

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!