angular2-web-worker icon indicating copy to clipboard operation
angular2-web-worker copied to clipboard

Allow asynchronous work in the worker

Open clementprdhomme opened this issue 7 years ago • 6 comments

Hi Haochi!

First of all, thank you for the library! It is really easy to use and it saves a lot of time.

In my project, we want to convert files to base64 strings. As these operations can be really heavy, I wanted to do the work in a webworker. The issue I've been dealing with is that the conversion to a string is asynchronous and your library doesn't let us do asynchronous work in the worker.

I implemented my own solution but I wonder if that wouldn't be useful for other people to have it included in your library?

Temporal solution

It consists in extending your service and overriding the createWorkerUrl method to pass postMessage as an argument :

import { WebWorkerService as service } from 'angular2-web-worker';

export class WebWorkerService extends service {

  // We override the method to enable postMessage to be called whenever we want
  // This allows us to asynchronously trigger postMessage
  private createWorkerUrl(resolve: Function): string {
    const resolveString = resolve.toString();
    // The change is here: postMessage is passed as argument
    const webWorkerTemplate = `
        self.addEventListener('message', function(e) {
            (${resolveString})(postMessage, e.data);
        });
    `;
    const blob = new Blob([webWorkerTemplate], { type: 'text/javascript' });
    return URL.createObjectURL(blob);
  }
}

Then I use it this way:

import { WebWorkerService } from 'app/services/webworker.service';

export class Example {

  // [...]

  // This method is called at some point
  async convertFile(file: File) {
    const base64 = await this.webWorkerService.run(this.workerFunction, file);
    console.log(base64);
  }

  workerFunction(postMessage: Function, file: File): void {
    const fileReader = new FileReader();

    fileReader.addEventListener('load', ({ target}: Event) => {
      postMessage((<FileReader>target).result);
    });

    fileReader.readAsDataURL(file);
  }

}

Thank you!

clementprdhomme avatar May 08 '17 12:05 clementprdhomme

@clementprdhomme Ahh interesting. I haven't thought of this use case. I will play around with your implementation. Thanks!

haochi avatar May 10 '17 17:05 haochi

Hi @haochi , Any update on this? Are you planning to implement the asynchronous implementation in the worker? My use case needs it too, so for now I am going with @clementprdhomme solution.

navcoder avatar Jun 01 '17 06:06 navcoder

@navcoder just started a new job this week. I will try to add support over the weekend 😅

haochi avatar Jun 01 '17 07:06 haochi

Thanks @haochi . One more thing, I am using tyepscript+ gulp + SystemJs for module loading. After installing angular2-web-worker using npm install, it created a folder named "angular2-web-worker" inside node_modules. But when trying to import in my app.component using import { WebWorkerService } from 'angular2-web-worker'; it doesn't recognize this module. So I had to manually add an index.d.ts file inside the "angular2-web-worker" folder containing line export { WebWorkerService } from './web-worker.service'; Now my app.component.ts recognizes the module. Am I doing it the right way or missing something?

navcoder avatar Jun 01 '17 10:06 navcoder

So.. this is still unimplemented.

christofferfleat avatar Apr 15 '19 09:04 christofferfleat

@christofferfleat Feel free to submit a PR.

haochi avatar Apr 24 '19 16:04 haochi