admin管理员组

文章数量:1415637

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

本文标签: javascriptHow to write a Promise wrapper around Web Workers APIStack Overflow