Is it feasible to use web worker (multi-threading)

2020-05-08 08:47发布

问题:

I'm currently develop an App that is based on NativeScript and Angular2.

My screen freeze for while when my App fetching data through HTTP, and I'd like to put the fetching action into another thread.

I did a lot of search on the web, and all I got is the code in javascript like the official doc - https://docs.nativescript.org/angular/core-concepts/multithreading-model.html

Is there any way to implement the muli-threading with WebWorker in "Typescript"(which contain the support of Angular injected HTTP service) instead of the "Javascript" code(the code from the official doc)

It's appreciated if someone could give me some guide or hint, and it'll be great if I could got some relative example code. Thanks.

回答1:

There shouldn't be any big draw back for using WebWorkers in {N} + Angular but be aware that currently the WebWorker is not "exactly" compatible with Angular AoT compilation.

For me when creating an WebwWrker (var myWorker = new Worker('~/web.worker.js');) throws and error after bundling the application with AoT. I have seen soem talk about this in the community and possible the way to fix this is by editing the webpack.common.js and adding an "loaded" like so:

{
    test: /\.worker.js$/,
    loaders: [
    "worker-loader"
    ]
}

Disclaimer: I have not tried this approach for fixing the error.



回答2:

If someone have some problems adding workers in Nativescript with Angular and Webpack, you must follow the steps listed here.

Keep special caution in the next steps:

  • When you import the worker, the route to the worker file comes after nativescript-worker-loader!.

  • In the webpack.config.js keep caution adding this piece of code:

     {
         test: /.ts$/, exclude: /.worker.ts$/, use: [
             "nativescript-dev-webpack/moduleid-compat-loader",
             "@ngtools/webpack",
         ]
     },
    

because is probable that you already have configured the AoT compilation, like this:

{
    test: /(?:\.ngfactory\.js|\.ngstyle\.js|\.ts)$/,
    use: [
        "nativescript-dev-webpack/moduleid-compat-loader",
        "@ngtools/webpack",
    ]
},

and you only need to add the exclude: /.worker.ts$/,

  • Finally, there is an example of a worker, in this case it use an Android native library:

    • example.worker.ts:

       import "globals";
       const context: Worker = self as any;
      
       declare const HPRTAndroidSDK;
      
       context.onmessage = msg => {
           let request = msg.data;
           let port = request.port;
           let result = HPRTAndroidSDK.HPRTPrinterHelper.PortOpen("Bluetooth," + port.portName);
           context.postMessage(result);
       };
      
    • example.component.ts (../../workers/example.worker is the relative route to my worker):

      import * as PrinterBTWorker from "nativescript-worker-loader!../../workers/example.worker";
      import ...
      
      connect(printer: HPRTPrinter): Observable<boolean> { 
          if (this.isConnected()){
              this.disconnect(); //Disconnect first if it's already connected
          }
          return Observable.create((observer) => {
              const worker = new PrinterBTWorker();
              worker.postMessage({ port: printer });
      
              worker.onmessage = (msg: any)  => {
                  worker.terminate();
                  if (msg.data == 0) { // 0: Connected, -1: Disconnected
                      observer.next(true);
                  }
                  else {
                      observer.next(false);
                  }
              };
      
              worker.onerror = (err) => {
                  worker.terminate();
                  observer.next(false);
              }
          }).pipe(timeout(5000), catchError(err => of(false)));
      }
      

Note: I use an Observable to make my call to the worker async and to add a timeout to the call to the native code, because in the case that it is not possible to connect to the printer (ex. it's turned off), it takes almost 10 seconds to notify, and this caused in my case the frezing of the app for all that time.

Important: It seem that it's necessary to run again the code manually every time that a change is made, because the worker isn't compiled using AoT.