[英]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中創建了一個工人封裝。 盡管由於我尚未清除它內置的某些依賴項,它可能無法立即使用。 隨意使用我應用的方法。
附加:你需要你的地圖post
並onmessage
你的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.