7

I would like to use the Web Worker facility introduced in Firefox 3.5 to enhance a Greasemonkey script I'm working on.

Is this even possible?

I've done some experimentation, but I can't get past the issue of loading a worker script from an arbitrary domain.

For example, this does not work:

var myWorker = new Worker("http://dl.getdropbox.com/u/93604/js/worker.js");

This code generates an error message in my Firebug console:

Failed to load script: http://dl.getdropbox.com/u/93604/js/worker.js (nsresult = 0x805303f4)

Apparently there's a limitation that does not allow you to start a worker from a URL that's not relative to the base URL of the calling script. You can load a worker script at a relative URL like this just fine:

var myWorker = new Worker("worker.js");

But there's no way for me to get the worker script on the user's filesystem so that it could be at a path relative to the calling script.

Am I screwed here? Should I give up on trying to use workers within my Greasemonkey script?

mattblodgett
  • 285
  • 4
  • 11

3 Answers3

12

For years I thought it wasn't possible to use web workers in GM. Of course the first idea was to use data-urls. But the Worker constructor didn't seem to accept them.

Today I tried it again and it worked without any problems at first. Only when I started to use functions of the GM API the Worker constructor stopped working.

Seemingly Firefox has a bug that prevents you from accessing Worker from a sandbox with X-ray vision. Even evaluating typeof Worker throws an exception. So the only way to use workers is to get the unwrapped version from the unwrapped window:

var echoWorker = new unsafeWindow.Worker("data:text/javascript," +
    "self.onmessage = function(e) {\n" +
    "    self.postMessage(e.data);\n" +
    "};"
);

Of course you have to be careful about special characters. It's better to encode the script with base64:

var dataURL = 'data:text/javascript;base64,' + btoa(script);
var worker = unsafeWindow.Worker(dataURL);

Alternatively you can also use blob-urls:

var blob = new Blob([script], {type: 'text/javascript'});
var blobURL = URL.createObjectURL(blob);
var worker = new unsafeWindow.Worker(blobURL);
URL.revokeObjectURL(blobURL);

If you really want to use a script hosted on a different domain that's not a problem because same origin policy doesn't apply for GM_xmlhttpRequest:

function createWorkerFromExternalURL(url, callback) {
    GM_xmlhttpRequest({
        method: 'GET',
        url: url,
        onload: function(response) {
            var script, dataURL, worker = null;
            if (response.status === 200) {
                script = response.responseText;
                dataURL = 'data:text/javascript;base64,' + btoa(script);
                worker = new unsafeWindow.Worker(dataURL);
            }
            callback(worker);
        },
        onerror: function() {
            callback(null);
        }
    });
}
Robert
  • 2,603
  • 26
  • 25
5

By now (10 years later), it's possible to use Web Workers with Firefox 77 and Tampermonkey. I've tested sucessfully using inline workers:

var blob = new Blob(["onmessage = function(e){postMessage('whats up?');console.log(e.data)}"], {type: 'text/javascript'})

var url = URL.createObjectURL(blob)

var worker = new Worker(url)

worker.onmessage = function(e){
  console.log(e.data) 
}

worker.postMessage('hey there!')

With Chrome or other extension like Greasemonkey ou Violentmonkey, i'ts not working because of CSP worker-src (see violation cases at https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/worker-src). This is why is not possible to use HTTP URLs or string as argument of Worker constructor, only works with blob URLs in this very specific case.

Still, there is a catch about the context of Workers. They can't access DOM, window, document or parent objects (see features available to workers at https://www.html5rocks.com/en/tutorials/workers/basics/).

Andre Lopes
  • 99
  • 1
  • 4
  • Seems to work in Firefox+ViolentMonkey now as well :) (got `whats up?` `hey there!` `hey there!`) – thomasa88 Jul 31 '21 at 13:28
  • Can't say why the worker's onmessage seems to run twice though.. edit: Actually, it seems to be the log that is output twice.. (script is run twice?) – thomasa88 Jul 31 '21 at 13:39
3

See:

Can I load a web worker script from an absolute URL?

Community
  • 1
  • 1
Zac Bowling
  • 6,508
  • 1
  • 27
  • 26
  • 1
    The context of Greasemonkey makes it unique, in my opinion. Greasemonkey is known to enable scenarios that aren't generally possible, like cross-domain Ajax requests. Maybe other Greasemonkey users are aware of tricks that could help me. – mattblodgett Oct 11 '09 at 03:49
  • There are some hacks people wrote for the Gears WorkerPool code (Check out the cross origin flag: http://code.google.com/apis/gears/api_workerpool.html#cross_origin ) . Greasemonkey also runs in the domain of an extension in Firefox so the guide on Workers inside Extensions on the MDC archive might help. Might be able to load a JS via the chrome:: url. – Zac Bowling Oct 11 '09 at 04:20
  • The only way greasemonkey can make it unique is if greasemonkey adds code for it to be unique. The greasemonkey script is only going to be able to load scripts from the same origin, which is why it's failing. – sdwilsh Oct 11 '09 at 15:36
  • But since Greasemonkey makes cross-domain Ajax requests possible, you can download the script first and then run it without restrictions. – Robert Oct 26 '13 at 00:30