Angular 8 Web Workers


Web Workers 使 JavaScript 应用程序可以在后台运行 CPU 密集型应用程序,从而使应用程序主线程专注于 UI 的流畅运行。 Angular 支持在应用程序中包含 Web 工作者。让我们编写一个简单的 Angular 应用程序并尝试使用 Web Worker。

使用以下命令创建一个新的 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)

Here,

  • 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"
    ]
}

Here,

tsconfig.worker.json 扩展了 tsconfig.json 并包含编译 web worker 的选项。

// tsconfig.app.json [只有一个片段]
"exclude": [
    "src/test.ts",
    "src/**/*.spec.ts",
    "src/**/*.worker.ts"
]

Here,

基本上,它将所有工作人员排除在编译之外,因为它具有单独的配置。

// angular.json (只是一个片段) "webWorkerTsConfig": "tsconfig.worker.json"

Here,

angular.json 包含 web worker 配置文件 tsconfig.worker.json。

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

Here,

创建了一个Web Workers。 Web Worker 基本上是一个函数,它会在消息事件被触发时被调用。 Web Worker 将接收调用者发送的数据,对其进行处理,然后将响应发送回调用者。

// src/app/app.component.ts [只有一个片段]
if (typeof Worker !== 'undefined') {
    //  创建一个新的
    const worker = new Worker('./app.worker', { type: 'module' });
    worker.onmessage = ({ data }) => {
        console.log(`page got message: ${data}`);
    };
    worker.postMessage('hello');
} else {

    // 此环境不支持 Web Worker。
    // 你应该添加一个回退,以便你的程序仍然正确执行。
}

Here,

  • AppComponent 创建一个新的worker实例,创建一个回调函数来接收响应,然后将消息发布给worker。

重新启动应用程序。由于更改了 angular.json 文件,Angular runner 没有看到,因此需要重新启动应用程序。否则,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;
    }
}

Here,

  • isPrimeNumber 检查给定数字是否为素数。
  • findNthPrimeNumber 找到第 n 个素数。

将新创建的素数类导入 src/app/app.worker.ts 并更改 web worker 的逻辑以查找第 n 个素数。

// / 

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

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

Change 应用组件 并包括两个功能, find10thPrimeNumber and 找到第 10000 个素数 .

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') {
            //  创建一个新的
            const worker = new Worker('./app.worker', { type: 'module' });
            worker.onmessage = ({ data }) => {
            this.prime10000 = data;
            };
            worker.postMessage(10000);
        } else {
            // 此环境不支持 Web Worker。
            // 你应该添加一个回退,以便你的程序仍然正确执行。
        }
    }
}

Here,

find10thPrimeNumber 直接使用 PrimeCalculator。但是,find10000thPrimeNumber 将计算委托给 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>

Here,

找到第 10000 个素数需要几秒钟,但它不会影响其他进程,因为它使用 web 工作者。试着先找到第 10000 个素数,然后再找到第 10 个素数。

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

申请结果如下:

应用程序的初始状态。

Workers

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

Web worker

两个过程都完成了。

Web workers

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