Search code examples
javascriptjqueryjquery-deferredworker

javascript jquery deferred not working with worker?


I have the following javascript code:

var promises = [];

    // Entries contains an unknown amount of items. For the sake of this
    // sample, it has five.
$.each(entries, function() {
    promises.push(doProcessing());
});

return $.when.apply($, promises).done(function() {
    alert('success');
}).fail(function() {
    alert('failed');
});

If my doProcessing function is:

function doProcessing() {
    var def = $.Deferred();

    setTimeout(function () {
        console.log('Request completed');
        def.resolve();
    },2000);

    return def.promise();
} // End of doProcessing

I get my Request completed log five times, followed by a 'success' alert. If I change my doProcessing method to be:

function doProcessing() {
    var def = $.Deferred();

    // Worker has a message
    myWorker.onmessage = function(event) {
      console.log('Worker finished');
      def.resolve();
      console.log(def);
    };

    myWorker.postMessage({action:'doSomething'});

    return def.promise();
} // End of doProcessing

Where my worker is now doing some processing and resolving the deferred, then I no longer get my success alert. I DO get five Worker finished messages, and my def object is also logged out.

I'm not sure what I'm doing wrong here. Could anyone point me in the right direction?


Solution

  • I DO get five Worker finished messages, and my def object is also logged out.

    But it's the same def object. By

     myWorker.onmessage = function(event) {
         …
     }
    

    you are overwriting the .onmessage property, and only the last listener will be called - by all 5 events. Instead, do something like

    worker.messages = 0;
    function doProcessing() {
        var def = $.Deferred(),
            id = worker.messages++;
    
        // Worker has a message
        myWorker.addEventListener("message", function l(event) {
            if (event.data.id != id) return; // It's not for us!
            console.log('Worker '+id+' finished');
            def.resolve(event.data);
            worker.removeEventListener(l);
        });
    
        myWorker.postMessage({action:'doSomething', id:id});
    
        return def.promise();
    }
    

    and adapt the worker code so that it does pass the id back.