Angular 8 - Web Worker 技术

使用 Web Worker 技术可以极大的提高 Angular 应用程序的计算性能,通过多线程执行 JavaScript 代码,避免了单线程阻塞的问题。Web Workers 使 JavaScript 应用程序能够使 CPU 密集在后台运行,以便应用程序主线程专注于 UI 的流畅运行。 Angular 提供了在应用程序中包含 Web Worker 的支持。 让我们编写一个简单的 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 Worker 的选项。

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

这里,

基本上,它会排除所有工作线程进行编译,因为它具有单独的配置。

// 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 创建一个新的工作线程实例,创建一个回调函数来接收响应,然后将消息发布给工作线程。

重新启动应用程序。 由于 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并包含两个函数,find10thPrimeNumberfind10000thPrimeNumber

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 个素数需要几秒钟,但不会影响其他进程,因为它使用网络工作线程。 只需尝试先找到第 10000 个质数,然后再找到第 10 个质数。

由于 Web Worker 正在计算第 10000 个质数,因此 UI 不会冻结。 我们可以同时检查第 10 个素数。 如果我们没有使用 Web Worker,我们就无法在浏览器中执行任何操作,因为它正在主动处理第 10000 个素数。

申请结果如下 −

应用程序的初始状态。

Workers

单击并尝试找到第 10000 个素数,然后尝试找到第 10 个素数。 该应用程序非常快速地找到第 10 个素数并显示它。 应用程序仍在后台处理以查找第 10000 个素数。

Web Worker

两个过程都已完成。

Web Worker

Web Worker 通过在后台执行复杂的操作来增强 Web 应用程序的用户体验,这在 Angular 应用程序中也很容易做到。