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?
See:
Can I load a web worker script from an absolute URL?
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);
}
});
}
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/).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With