最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to write a Promise wrapper around Web Workers API? - Stack Overflow

programmeradmin1浏览0评论

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

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

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

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!

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

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

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

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!

Share Improve this question asked Aug 14, 2019 at 13:44 user11276880user11276880
Add a ment  | 

1 Answer 1

Reset to default 7

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

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

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

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

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).

发布评论

评论列表(0)

  1. 暂无评论