Is it possible to use workers in a Greasemonkey script?

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

See:

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