haochi / angular2-web-worker

Web worker for Angular 2
https://www.npmjs.com/package/angular2-web-worker
51 stars 10 forks source link

Allow asynchronous work in the worker #9

Open clementprdhomme opened 7 years ago

clementprdhomme commented 7 years ago

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!

haochi commented 7 years ago

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

navcoder commented 7 years ago

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.

haochi commented 7 years ago

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

navcoder commented 7 years ago

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?

christofferfleat commented 5 years ago

So.. this is still unimplemented.

haochi commented 5 years ago

@christofferfleat Feel free to submit a PR.