在 JavaScript 闭包中使用 promise 与 web worker 一起工作

Using promise to work with web worker inside a JavaScript closure

我在 JavaScript 中执行了一个图像处理操作,它按预期工作,但有时它会冻结 UI,这让我不得不使用 Web worker 来执行图像处理职能。 我有一个需要处理多个的场景。以下是我用来实现上述壮举的工作流程摘要。

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

在这里,我正在加载多个图像并将它们传递到 manipulate 函数中。 在这种情况下,我在这里面临的问题是,有时对于少数图像,Promise 并非永远无法解决。 在调试我的代码后,我发现这是因为我正在为图像创建一个 Promise,而之前的 Promise 没有得到解决。 我需要关于如何解决这个问题的建议,我还有另一个问题,我是否应该多次使用相同的闭包(在上面的场景中使用过滤器),或者每次需要时都创建新的闭包,如下所示:

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

} 

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

我希望我的问题很清楚,如果没有请评论。

更好的方法是只加载图像处理 Worker 一次。在您的应用程序启动期间或需要时。

之后,您可以只为您希望从 worker 调用的函数创建一个 Promise。在你的例子中,每次你 post 到 Worker 时,filter 可以 return 一个新的 Promise 对象。仅当从 worker 收到特定函数调用的回复时,才应解析此 promise 对象。

您的代码发生的情况是,即使 onmessage 处理程序正在处理来自 Worker 的不同消息,您的承诺仍在解决。 IE。如果你 post 2次给工人。如果第二个 post return 是一条消息,它会自动解析您的两个承诺对象。

我这里创建了一个worker封装Orc.js。虽然它可能无法开箱即用,因为我还没有清除它内置的一些依赖项。随意使用我应用的方法。

补充: 您需要将 postonmessage 映射到 promises。这也将要求您修改您的 Worker 代码。

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