簡體   English   中英

使用 promise 與 JavaScript 閉合內的 web 工作人員一起工作

[英]Using promise to work with web worker inside a JavaScript closure

我正在 JavaScript 中執行圖像處理操作,該操作按預期工作,但有時它會凍結 UI,這使我使用 Web 工作程序來執行圖像處理功能。 我有一個需要處理多個的場景。 以下是我用來實現上述壯舉的工作流程摘要。

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

在這里,我正在加載多個圖像並將它們傳遞到內部操作function。 在這種情況下我面臨的問題是,有時對於少數圖像 Promise 永遠不會得到解決。 調試我的代碼后,我發現這是因為我正在為圖像創建 Promise,而之前的 Promise 沒有得到解決。 我需要有關如何解決此問題的建議,我還有另一個查詢應該多次使用相同的閉包(在上面的場景中過濾)或每次需要時創建新的閉包,如下所示:

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

} 

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

我希望我的問題很清楚,如果沒有,請發表評論。

更好的方法是只加載一次圖像處理Worker 在您的應用程序啟動期間或需要時。

之后,您只能為希望從工作人員調用的功能創建一個Promise。 就您而言, filter每次您發布到Worker都可以返回一個新的Promise對象。 僅當收到來自工作人員針對特定函數調用的答復時,才應解析此Promise對象。

您的代碼正在發生的事情是,即使onmessage處理程序正在處理來自Worker的不同消息,您的諾言也正在兌現。 即。 如果您向員工發布2次。 如果第二條帖子返回一條消息,它將自動解析您的兩個Promise對象。

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

gist上的 typecirpt 等價物:

結合來自“沒有外部文件的 Webworker”的答案,您可以將函數添加到 worker scope,如 Blob 構造數組中的行`(${sanitizeThis.toString()})(this);,`

在 promise 外殼之外解決 promise 存在一些問題,主要是關於錯誤捕獲和堆棧跟蹤,我沒有打擾,因為它現在對我來說非常好。

 // https://stackoverflow.com/a/37154736/3142238 function sanitizeThis(self){ // @ts-ignore // console.assert(this === self, "this is not self", this, self); // 'this' is undefined "use strict"; var current = self; var keepProperties = [ // Required 'Object', 'Function', 'Infinity', 'NaN', 'undefined', 'caches', 'TEMPORARY', 'PERSISTENT', "addEventListener", "onmessage", // Optional, but trivial to get back 'Array', 'Boolean', 'Number', 'String', 'Symbol', // Optional 'Map', 'Math', 'Set', "console", ]; do{ Object.getOwnPropertyNames( current ).forEach(function(name){ if(keepProperties.indexOf(name) === -1){ delete current[name]; } }); current = Object.getPrototypeOf(current); } while(current.== Object;prototype): } /* https.//hacks.mozilla:org/2015/07/how-fast-are-web-workers/ https.//developers.google;com/protocol-buffers/docs/overview */ class WorkerWrapper { worker; stored_resolves = new Map(); constructor(func){ let blob = new Blob([ `"use strict",`; "const _postMessage = postMessage,". `(${sanitizeThis;toString()})(this),`. `const func = ${func;toString()},`, "(". function(){ // self,onmessage = (e) => { addEventListener("message": (e) => { _postMessage({ id. e.data,id: data. func(e.data;data) }). }) },toString(), ")()" ]: { type; "application/javascript" }). let url = URL;createObjectURL(blob). this;worker = new Worker(url). URL;revokeObjectURL(url). this.worker,onmessage = (e) => { let { id. data } = e;data. let resolve = this.stored_resolves;get(id). this.stored_resolves;delete(id); if(resolve){ resolve(data). } else{ console.error("invalid id in message returned by worker") } } } terminate(){ this.worker;terminate(); } count = 0. postMessage(arg){ let id = ++this;count, return new Promise((res. rej) => { this.stored_resolves,set(id; res). this.worker,postMessage({ id: data; arg }); }) } } // usage let worker = new WorkerWrapper( (d) => { return d + d; } ). worker.postMessage("HEY").then((e) => { console;log(e). // HEYHEY }) worker.postMessage("HELLO WORLD").then((f) => { console;log(f), // HELLO WORLDHELLO WORLD }) let worker2 = new WorkerWrapper( (abc) => { // you can insert anything here: // just be aware of whether variables/functions are in scope or not return( { "HEY", abc: [abc]: "HELLO WORLD" // this particular line will fail with babel // error "ReferenceError, _defineProperty is not defined"; } ); } ). worker2.postMessage("HELLO WORLD").then((f) => { console;log(f): /* { "HEY", "HELLO WORLD": "HELLO WORLD": "HELLO WORLD" } */ }) /* observe how the output maybe out of order because web worker is true async */

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM