Angular - Web Workers



Web Workers 允許 JavaScript 應用程式在後臺執行 CPU 密集型任務,以便應用程式主執行緒專注於 UI 的流暢執行。Angular 提供了對在應用程式中包含 Web Workers 的支援。讓我們編寫一個簡單的 Angular 應用程式並嘗試使用 Web Workers。

使用以下命令建立一個新的 Angular 應用程式:

cd /go/to/workspace
ng new web-worker-sample

使用以下命令執行應用程式:

cd web-worker-sample
npm run start

使用以下命令新增新的 Web Worker:

ng generate web-worker app

上述命令的輸出如下:

CREATE tsconfig.worker.json (212 bytes)
CREATE src/app/app.worker.ts (157 bytes)
UPDATE tsconfig.app.json (296 bytes)
UPDATE angular.json (3776 bytes)
UPDATE src/app/app.component.ts (605 bytes)

這裡:

  • app 指的是要建立的 Web Worker 的位置。
  • Angular CLI 將生成兩個新檔案,tsconfig.worker.json 和 src/app/app.worker.ts,並更新三個檔案:tsconfig.app.json、angular.json 和 src/app/app.component.ts。

讓我們檢查一下更改:

// tsconfig.worker.json
{
   "extends": "./tsconfig.json",
   "compilerOptions": {
      "outDir": "./out-tsc/worker",
      "lib": [
         "es2018",
         "webworker"
      ],


      "types": []
   },
   "include": [
      "src/**/*.worker.ts"
   ]
}

這裡:

tsconfig.worker.json 擴充套件了 tsconfig.json 幷包含編譯 Web Workers 的選項。

// tsconfig.app.json [only a snippet]
"exclude": [
   "src/test.ts",
   "src/**/*.spec.ts",
   "src/**/*.worker.ts"
]

這裡:

基本上,它排除了所有 worker 的編譯,因為它有單獨的配置。

// angular.json (only a snippet) "webWorkerTsConfig": "tsconfig.worker.json"

這裡:

angular.json 包含 Web Worker 配置檔案 tsconfig.worker.json。

// src/app/app.worker.ts
addEventListener('message', ({ data }) => {
   const response = `worker response to ${data}`;
   postMessage(response);
});

這裡:

建立了一個 Web Worker。Web Worker 本質上是一個函式,當觸發訊息事件時將被呼叫。Web Worker 將接收呼叫方傳送的資料,處理它,然後將響應傳送回撥用方。

// src/app/app.component.ts [only a snippet]
if (typeof Worker !== 'undefined') {
   // Create a new
   const worker = new Worker('./app.worker', { type: 'module' });
   worker.onmessage = ({ data }) => {
      console.log(`page got message: ${data}`);
   };
   worker.postMessage('hello');
} else {

   // Web Workers are not supported in this environment.
   // You should add a fallback so that your program still executes correctly.
}

這裡:

  • AppComponent 建立一個新的 worker 例項,建立一個回撥函式來接收響應,然後將訊息釋出到 worker。

重新啟動應用程式。由於 angular.json 檔案已更改,而 Angular 執行程式未監視該檔案,因此有必要重新啟動應用程式。否則,Angular 無法識別新的 Web Worker 並且不會編譯它。

讓我們建立一個 Typescript 類 src/app/app.prime.ts 來查詢第 n 個素數。

export class PrimeCalculator
{
   static isPrimeNumber(num : number) : boolean {
      if(num == 1) return true;

      let idx : number = 2;
      for(idx = 2; idx < num / 2; idx++)
      {
         if(num % idx == 0)
            return false;
      }

      return true;
   }

   static findNthPrimeNumber(num : number) : number {
      let idx : number = 1;
      let count = 0;

      while(count < num) {
         if(this.isPrimeNumber(idx))
            count++;

         idx++;
         console.log(idx);
      }

      return idx - 1;
   }
}

這裡:

  • isPrimeNumber 檢查給定數字是否為素數。
  • findNthPrimeNumber 查詢第 n 個素數。

將新建立的素數類匯入到 src/app/app.worker.ts 中,並將 Web Worker 的邏輯更改為查詢第 n 個素數。

/// <reference lib="webworker" />

import { PrimeCalculator } from './app.prime';

addEventListener('message', ({ data }) => {
   // const response = `worker response to ${data}`;
   const response = PrimeCalculator.findNthPrimeNumber(parseInt(data));
   postMessage(response);
});

更改 **AppComponent** 幷包含兩個函式 **find10thPrimeNumber** 和 **find10000thPrimeNumber**。

import { Component } from '@angular/core';
import { PrimeCalculator } from './app.prime';

@Component({
   selector: 'app-root',
   templateUrl: './app.component.html',
   styleUrls: ['./app.component.css']
})
export class AppComponent {
   title = 'Web worker sample';
   prime10 : number = 0;
   prime10000 : number = 0;

   find10thPrimeNumber() {
      this.prime10 = PrimeCalculator.findNthPrimeNumber(10);
   }

   find10000thPrimeNumber() {
      if (typeof Worker !== 'undefined') {
         // Create a new
         const worker = new Worker('./app.worker', { type: 'module' });
         worker.onmessage = ({ data }) => {
         this.prime10000 = data;
         };
         worker.postMessage(10000);
      } else {
         // Web Workers are not supported in this environment.
         // You should add a fallback so that your program still executes correctly.
      }
   }
}

這裡:

find10thPrimeNumber 直接使用 PrimeCalculator。但是,find10000thPrimeNumber 將計算委託給 Web Worker,而 Web Worker 又使用 PrimeCalculator。

更改 AppComponent 模板 src/app/app.commands.html 幷包含兩個選項,一個用於查詢第 10 個素數,另一個用於查詢第 10000 個素數。

<h1>{{ title }}</h1>

<div>
   <a href="#" (click)="find10thPrimeNumber()">Click here</a> to find 10th prime number
   <div>The 10<sup>th</sup> prime number is {{ prime10 }}</div> <br/>
   <a href="#" (click)="find10000thPrimeNumber()">Click here</a> to find 10000th prime number
   <div>The 10000<sup>th</sup> prime number is {{ prime10000 }}</div>
</div>

這裡:

查詢第 10000 個素數將花費幾秒鐘,但它不會影響其他程序,因為它使用 Web Workers。先嚐試查詢第 10000 個素數,然後再查詢第 10 個素數。

由於 Web Worker 正在計算第 10000 個素數,因此 UI 不會凍結。我們可以在此期間檢查第 10 個素數。如果我們沒有使用 Web Worker,我們無法在瀏覽器中執行任何操作,因為它正在積極處理第 10000 個素數。

應用程式的結果如下:

應用程式的初始狀態。

Workers

單擊並嘗試查詢第 10000 個素數,然後嘗試查詢第 10 個素數。應用程式很快找到第 10 個素數並顯示它。應用程式仍在後臺處理以查詢第 10000 個素數。

Web worker

兩個程序都已完成。

Web workers

Web Worker 透過在後臺執行復雜操作來增強 Web 應用程式的使用者體驗,並且在 Angular 應用程式中也很容易實現。

廣告