在现代前端中使用 Worker

本文最后更新于:2020年4月20日 下午

场景

由于需要在 Browser 进行大量的计算,所以吾辈开始尝试使用 webworker 分离 CPU 密集型的计算操作,最终找到了 comlink 这个库,但之前在 vue 中使用时发生了错误,目前看起来已经得到了解决,所以在此记录一下。

调研方案

  • web-worker-proxy:结合了 proxy/promise/webworker 的强大工具库,但如何在 ts 中使用却是个问题
  • Orc.js:一个简单的 worker 封装
  • VueWorker:结合 vue 的 worker 封装,无法理解,难道真的会有人在 vue 组件中进行大量计算么?
  • comlink:Chrome 的一个基于 proxy/promise/webworker 的封装库
  • worker-plugin:和上面的同属 chrome 实验室的一个 webpack 插件

最后决定使用 comlink 结合 worker-plugin 实现简单的 worker 使用。

相关问题:comlink-loader 工作不正常

使用步骤

添加相关依赖

1
2
yarn add comlink
yarn add -D worker-plugin

在 webpack 中添加插件

1
2
3
{
plugins: [new WorkerPlugin()];
}

这里一般不需要配置,如果需要,可以参考:worker-plugin

添加一个简单的 hello.worker.ts

1
2
3
4
5
6
7
8
9
10
11
12
import { expose } from "comlink";
import { HelloWorker } from "./hello.worker.type";

const obj = {
counter: 0,
inc() {
this.counter++;
},
info: { city: "GZ" },
};

expose(obj);

main.ts 中使用

1
2
3
4
const obj = wrap(new Worker("./hello.worker.ts", { type: "module" })) as any;
alert(`Counter: ${await obj.counter}`);
await obj.inc();
alert(`Counter: ${await obj.counter}`);

但这里并不是类型安全的,所以我们可以实现正确的类型。

添加一个 hello.worker.ts 暴露出来的类型 HelloWorkerType

1
2
3
4
5
6
7
export type HelloWorker = {
counter: number;
inc(): void;
info: {
city: string;
};
};

同时为了支持在 main.ts 中使用正确的类型,需要使用泛型

main.ts 修改如下

1
2
3
4
5
6
7
const obj = wrap<HelloWorker>(
new Worker("./hello.worker.ts", { type: "module" })
);
console.log(`Counter: ${await obj.counter}`);
await obj.inc();
console.log(`Counter: ${await obj.counter}`);
console.log(`Counter: ${await obj.info.city}`);

本质上这里使用 . 的方式访问 worker 中的内容依赖于 Proxy,所以不需要使用类似于 await (await obj.info).city 这种奇怪的代码。

参考:web workers 简介(二)动态创建 worker

参考