Using promise to work with web worker inside a JavaScript closure

泄露秘密 提交于 2019-12-25 00:01:46

问题


I was executing an image processing operation in JavaScript which was working as expected expect one thing that sometimes it was freezing the UI, which made me to use Web worker to excute the image processing functions. I have a scenario where i need to process multiple. Below is a summary of workflow which i am using to achieve the above feat.

//closure
var filter = (function(){
    function process(args){
         var promise = new Promise(function (resolve, reject) {
            if (typeof (Worker) !== "undefined") {
                if (typeof (imgWorker) == "undefined") {
                    imgWorker = new Worker("/processWorker.js");
                }
                imgWorker.postMessage(args);
                imgWorker.onmessage = function (event) {
                    resolve(event.data);
                };
            } else {
                reject("Sorry, your browser does not support Web Workers...");
            }
        });
        return promise;
    }
return {
        process: function(args){
            return process(args);
       }
 }
})(); 

function manipulate(args, callback){
    filter.process(args).then(function(res){
        callback(res);
    });
}

Here, i am loading multiple images and passing them inside manipulate function. The issue i am facing here in this scenario is that sometimes for few images Promise is not never resolved. After debugging my code i figured out that it is because i am creating a Promise for an image while previous Promise was not resolved. I need suggestions on how can i fix this issue, also i have another query should i use same closure(filter here in above scenario) multiple times or create new closure each time when required as below:

var filter = function(){
      ....
    return function(){}
    ....

} 

function manipulate(args, callback){
    var abc = filter();
    abc.process(args).then(function(res){
        callback(res);
    });
}

I hope my problem is clear, if not please comment.


回答1:


A better approach would be to load your image processing Worker once only. during the start of your application or when it is needed.

After that, you can create a Promise only for the function you wish to call from the worker. In your case, filter can return a new Promise object every time that you post to the Worker. This promise object should only be resolved when a reply is received from the worker for the specific function call.

What is happening with your code is that, your promises are resolving even though the onmessage handler is handling a different message from the Worker. ie. if you post 2 times to the worker. if the second post returns a message it automatically resolves both of your promise objects.

I created a worker encapsulation here Orc.js. Although it may not work out of the box due to the fact i haven't cleaned it of some dependencies i built into it. Feel free to use the methods i applied.

Additional: You will need to map your post and onmessage to your promises. this will require you to modify your Worker code as well.

//
let generateID = function(args){
  //generate an ID from your args. or find a unique way to distinguish your promises. 
  return id;
}
let promises =  {}
// you can add this object to your filter object if you like. but i placed it here temporarily

//closure
var filter = (function(){
    function process(args){
          let id = generateID(args)
          promises[id] = {}
          promises[id].promise = new Promise(function (resolve, reject) {
            if (typeof (Worker) !== "undefined") {
                if (typeof (imgWorker) == "undefined") {
                    imgWorker = new Worker("/processWorker.js");
                    imgWorker.onmessage = function (event) {
                        let id = generateID(event.data.args) //let your worker return the args so you can check the id of the promise you created.
                        // resolve only the promise that you need to resolve
                        promises[id].resolve(event.data);
                    }    
                    // you dont need to keep assigning a function to the onmessage. 
                }
               
                imgWorker.postMessage(args);
                // you can save all relevant things in your object. 
                promises[id].resolve = resolve
                promises[id].reject = reject
                promises[id].args = args
            } else {
                reject("Sorry, your browser does not support Web Workers...");
            }
        });
        //return the relevant promise
        return promises[id].promise;
    }
return {
        process: function(args){
            return process(args);
       }
}
})(); 

function manipulate(args, callback){
    filter.process(args).then(function(res){
        callback(res);
    });
}


来源:https://stackoverflow.com/questions/52438273/using-promise-to-work-with-web-worker-inside-a-javascript-closure

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!