如何围绕Web Workers API编写Promise包装器? [英] How to write a Promise wrapper around Web Workers API?

查看:44
本文介绍了如何围绕Web Workers API编写Promise包装器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一个利用Web Workers的库.库的使用者不应看到任何Web Worker内容,而应从该库的公共方法中返回Promise,如下所示:

I am writing a library which makes use of Web Workers. The consumer of the library should not see any of the Web Worker stuff and should instead get returned a Promise from the public methods of this library like this:

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

在我的库代码中,我有一个包装Web Worker逻辑的类.在构造函数中,我创建工作线程并设置消息"事件侦听器,以侦听来自工作线程的传入数据.同样在此类中,还有一个 doCalculation(input)方法,该方法对库的使用者是公共的.它接受输入并将其发送到工作线程以执行实际计算.

In my library code I have a class which wraps the Web Worker logic. In the constructor I create the worker and set the "message" event listener, listening for incoming data from the worker thread. Also in this class there is a doCalculation(input) method which is public to the consumer of the library. It takes the input and sends it to the worker thread to perform the actual calculation.

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

我现在的问题是,如何从持有 e.data doCalculation 方法返回一个Promise?

My question now is, how can I return a Promise from the doCalculation method holding e.data?

我的初衷是这样的,显然不起作用,因为每次调用 doCalculation 都会创建一个新的消息"事件侦听器.

My first intend was something like this which obviously doesn't work because a new "message" event listener is created with every call to 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);
      });
    }))
  }
}

这里的所有代码示例都经过简化,只是为了阐明我的观点.

All the code examples here are simplified to only make my point clear.

对于任何正确方向的提示,我将不胜感激!

I would be thankful for any hints into the right direction!

推荐答案

请确保您可以将 resolve 存储在某个地方,例如在一个对象中:

For sure you could store resolve somewhere, e.g. in an object:

 this.resolvers = {};
 this.count = 0; // used later to generate unique ids

然后针对发送给网络工作者的每个任务,创建一个唯一的ID,并在其中存储承诺解析器

Then for each task sent to the webworker, create a unique id, and store the promise resolver there

 const id = this.count++;
 // Send id and task to WebWorker
 return new Promise(resolve => this.resolvers[id] = resolve);

然后,当网络工作者发送消息时,从中获取ID并解决存储的诺言:

Then when the webworker sends a message, get the id from it, and resolve the stored promise:

 this.resolvers[ id ](data);
 delete this.resolvers[id]; // Prevent memory leak

这样(1)您只需要注册一个处理程序,(2)Webworker可以同时处理多个任务,并且(3)通过检查 Object.keys(this.resolvers).

That way (1) you only need to register one handler, (2) multiple tasks can be handled at the same time by the webworker and (3) You can easily determine which tasks are running on the webworker by checking the Object.keys(this.resolvers).

这篇关于如何围绕Web Workers API编写Promise包装器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆