内容简介:由于需要在 Browser 进行大量的(音频转解码)计算,所以吾辈开始尝试使用 webworker 分离 CPU 密集型的计算操作,最终找到了 comlink 这个库,但之前在 vue 中使用时发生了错误,目前看起来已经得到了解决,所以在此记录一下。最后决定使用 comlink 结合 worker-plugin 实现简单的 worker 使用。在 GitHub 上有
由于需要在 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 使用。
安装与配置
在 GitHub 上有 可运行示例 demo
相关问题: comlink-loader 工作不正常
添加相关依赖
yarn add comlink yarn add -D worker-plugin
在 webpack 配置中添加插件
{ plugins: [new WorkerPlugin()] }
这里一般不需要特殊参数配置,如果需要,可以参考: worker-plugin
示例
基本示例
添加一个简单的 hello.worker.ts
import { expose } from 'comlink' const obj = { counter: 0, inc() { this.counter++ }, } expose(obj)
在 main.ts
中使用
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
export interface HelloWorkerType { counter: number inc(): void }
同时为了支持在 main.ts 中使用正确的类型,需要使用泛型
main.ts 修改如下
const obj = wrap<HelloWorkerType>( new Worker('./hello.worker.ts', { type: 'module' }), ) alert(`Counter: ${await obj.counter}`) await obj.inc() alert(`Counter: ${await obj.counter}`)
纯函数
声明函数的类型 HelloCallback.worker.type.d.ts
type ListItem<T extends any[]> = T extends (infer U)[] ? U : never export type MapWorkerType = <List extends any[], U>( arr: List, cb: (val: ListItem<List>) => U | Promise<U>, ) => Promise<U[]>
声明一个纯函数 HelloCallback.worker.ts
import { MapWorkerType } from './HelloCallback.worker.type' import { expose } from 'comlink' export const map: MapWorkerType = (arr, cb) => Promise.all(arr.map(cb)) expose(map)
注:此处最好使用变量的形式,主要是为了方便将函数类型剥离出去。
在 main.ts 中使用
const map = wrap<MapWorkerType>( new Worker('./HelloCallback.worker.ts', { type: 'module', }), ) const list = await map( [1, 2, 3], proxy((i) => i * 2), ) console.log('list: ', list)
使用 class 的形式
声明接口 HelloClass.worker.type.d.ts
export class HelloClassWorker { sum(...args: number[]): number }
worker 文件 HelloClass.worker.ts
import { HelloClassWorker } from './HelloClass.worker.type' import { expose } from 'comlink' class HelloClassWorkerImpl implements HelloClassWorker { sum(...args: number[]): number { return args.reduce((res, i) => res + i, 0) } } expose(HelloClassWorkerImpl)
关于此处 implements class
的问题,吾辈偶然一试之下没报错也很奇怪,所以找到了相关问题 Typescript: How to extend two classes?
,官方文档也同样说明了这个特性 Mixins
。
在 main.ts 中使用
const HelloClassWorkerClazz = wrap<typeof HelloClassWorker>( new Worker('./HelloClass.worker.ts', { type: 'module', }), ) const instance = await new HelloClassWorkerClazz() console.log(await instance.sum(1, 2))
总结
总的来说,使用 worker 的基本分三步
- 编写需要放在 worker 里内容的类型定义
- 根据类型定义实现它
- 在主进程的代码中使用它
注:当然,如果是复杂的东西,可以直接在单独的文件中实现,然后声明一个 .worker.ts 暴露出去,不在 .worker.ts 中包含任何
参考
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。