如何围绕 Web Workers API 编写 Promise 包装器?
How to write a Promise wrapper around Web Workers API?
我正在编写一个使用 Web Worker 的库。库的使用者不应该看到任何 Web Worker 的东西,而应该从这个库的 public 方法中获得 returned 一个 Promise,如下所示:
// consumer.js
const api = new Api();
api.doCalculation(input1).then(data => console.log(data));
api.doCalculation(input2).then(data => console.log(data));
api.doCalculation(input3).then(data => console.log(data));
在我的库代码中,我有一个 class 包装了 Web Worker 逻辑。在构造函数中,我创建了工作线程并设置了 "message" 事件监听器,监听来自工作线程的传入数据。
在这个 class 中还有一个 doCalculation(input)
方法,它对库的使用者来说是 public 。它获取输入并将其发送到工作线程以执行实际计算。
// api.js
class Api {
constructor() {
this.worker = new Worker('worker.js');
this.worker.addEventListener('message', (e) => {
// I want to return this e.data from the doCalculation method
console.log(e.data);
});
}
doCalculation(input) {
this.worker.postMessage({input: input});
// I want to return a Promise from this method,
// holding the result e.data
}
}
我现在的问题是,我如何 return 来自 doCalculation
方法的 Promise 持有 e.data
?
我最初的打算是这样的,但显然行不通,因为每次调用 doCalculation
.
都会创建一个新的 "message" 事件侦听器
// api.js
class Api {
constructor() {
this.worker = new Worker('worker.js');
}
doCalculation(input) {
this.worker.postMessage({input: input});
return new Promise((resolve => {
this.worker.addEventListener('message', (e) => {
resolve(e.data);
});
}))
}
}
这里的所有代码示例都经过简化,只是为了阐明我的观点。
如能提供正确方向的任何提示,我将不胜感激!
当然可以将 resolve
存储在某处,例如在对象中:
this.resolvers = {};
this.count = 0; // used later to generate unique ids
然后为每个发送给 webworker 的任务创建一个唯一的 id,并将 promise 解析器存储在那里
const id = this.count++;
// Send id and task to WebWorker
return new Promise(resolve => this.resolvers[id] = resolve);
然后当webworker发送消息时,从中获取id,并解析存储的promise:
this.resolvers[ id ](data);
delete this.resolvers[id]; // Prevent memory leak
这样 (1) 您只需要注册一个处理程序,(2) webworker 可以同时处理多个任务,并且 (3) 您可以轻松确定哪些任务 运行 webworker 通过检查 Object.keys(this.resolvers)
.
我正在编写一个使用 Web Worker 的库。库的使用者不应该看到任何 Web Worker 的东西,而应该从这个库的 public 方法中获得 returned 一个 Promise,如下所示:
// consumer.js
const api = new Api();
api.doCalculation(input1).then(data => console.log(data));
api.doCalculation(input2).then(data => console.log(data));
api.doCalculation(input3).then(data => console.log(data));
在我的库代码中,我有一个 class 包装了 Web Worker 逻辑。在构造函数中,我创建了工作线程并设置了 "message" 事件监听器,监听来自工作线程的传入数据。
在这个 class 中还有一个 doCalculation(input)
方法,它对库的使用者来说是 public 。它获取输入并将其发送到工作线程以执行实际计算。
// api.js
class Api {
constructor() {
this.worker = new Worker('worker.js');
this.worker.addEventListener('message', (e) => {
// I want to return this e.data from the doCalculation method
console.log(e.data);
});
}
doCalculation(input) {
this.worker.postMessage({input: input});
// I want to return a Promise from this method,
// holding the result e.data
}
}
我现在的问题是,我如何 return 来自 doCalculation
方法的 Promise 持有 e.data
?
我最初的打算是这样的,但显然行不通,因为每次调用 doCalculation
.
// api.js
class Api {
constructor() {
this.worker = new Worker('worker.js');
}
doCalculation(input) {
this.worker.postMessage({input: input});
return new Promise((resolve => {
this.worker.addEventListener('message', (e) => {
resolve(e.data);
});
}))
}
}
这里的所有代码示例都经过简化,只是为了阐明我的观点。
如能提供正确方向的任何提示,我将不胜感激!
当然可以将 resolve
存储在某处,例如在对象中:
this.resolvers = {};
this.count = 0; // used later to generate unique ids
然后为每个发送给 webworker 的任务创建一个唯一的 id,并将 promise 解析器存储在那里
const id = this.count++;
// Send id and task to WebWorker
return new Promise(resolve => this.resolvers[id] = resolve);
然后当webworker发送消息时,从中获取id,并解析存储的promise:
this.resolvers[ id ](data);
delete this.resolvers[id]; // Prevent memory leak
这样 (1) 您只需要注册一个处理程序,(2) webworker 可以同时处理多个任务,并且 (3) 您可以轻松确定哪些任务 运行 webworker 通过检查 Object.keys(this.resolvers)
.