简体   繁体   中英

HTML5 Web Worker Communication

I'm trying to come up with a good way of calling functions in a web worker script and getting them to return values to the main script, I'm finding it kind of difficult to come up with something that is extensible since it's asynchronous and done via messaging, any help would be much appreciated. Here is my web worker script...

self.addEventListener('message', function(e) {
    var data = e.data;

    switch (data.cmd) {
        case 'call' :
            self[data.funcName](data.args);
            break;
        default:
            self.postMessage('Unknown command: ' + data.msg);
        };

}, false);

function testWorkerFunction(args) {
    self.postMessage({'cmd': 'call', 'funcName': 'testClientFunction', 'args': args});
}

And here is my main script.

$(function() {
    var someOtherVal;
    worker = new Worker('js/workers/uc-main-worker.js');

    worker.addEventListener('message', function(e) {
        console.log('Worker said: ', e.data);
        var data = e.data;

        switch (data.cmd) {
            case 'call' :
                self[data.funcName](data.args);
                break;
            default:
                console.log('Unknown command');
                break;
            };
    }, false);

    worker.onerror = function(e){
      throw new Error(e.message + " (" + e.filename + ":" + e.lineno + ")");
    };

    /* This is the bit I need some help with, how I can return a value back here */
    var someVal = messageWorker({'cmd': 'call', 'funcName': 'testWorkerFunction', 'args': 'hello'});
    //Not sure how to get a value back without invoking a function in the main script because I have to use messaging.

});

function messageWorker(message) {
    worker.postMessage(message);
}

function testClientFunction(args) {
    //Simply storing it as a global var.
    someOtherVal = args;
}

Hopefully from my code yo understand what I am after, at the moment I can get the value returned by the testWorkerFunction, but only by calling another function and or storing it as a global variable.

Communicating with Workers can't be done synchronously, as they run in a different thread. You have to use callbacks to achieve this communication.

If you want to make your code look more elegant than a callback "pyramid of doom", you can embrace the Promise pattern, and you can use Q or jQuery.deferred()

EDIT: You can change your messageWorker method to look like this if you want to use "cleaner" callbacks.

function messageWorker(message, callback) {
    function listen(e){
        if (e.data.funcName === message.funcName){
            worker.removeEventListener("message". listen);
            callback(e.data.args);
        }
    }
    worker.addEventListener("message", listen)
    worker.postMessage(message);
}

Take a look at the vkThread plugin. I think, it is what you're looking for. This plugin allows you to execute any function of a your code in a thread.

http://www.eslinstructor.net/vkthread/

Hope this helps,

--Vadim

(After failing to find a solution anywhere else) I've come up with a fairly straightforward pattern for communicating with a web worker via callbacks that need access to calling code: https://gist.github.com/therightstuff/eb415798b0e30866fe85d66af68969cf

EDIT: wow, looking back at my original post I wonder if I wasn't having a stroke at the time. The link has been updated

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM