在现代前端项目中使用 Worker

栏目: IT技术 · 发布时间: 5年前

内容简介:由于需要在 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 的基本分三步

  1. 编写需要放在 worker 里内容的类型定义
  2. 根据类型定义实现它
  3. 在主进程的代码中使用它

注:当然,如果是复杂的东西,可以直接在单独的文件中实现,然后声明一个 .worker.ts 暴露出去,不在 .worker.ts 中包含任何

参考


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

软件预构艺术(中文版)

软件预构艺术(中文版)

Ken Pugh / O'Reilly Taiwan公司 / 东南大学 / 2010-6 / 26.00元

利用经验累积而得到的洞察力开发新的解决方案被称为预构。透过重构而获得的专业知识也属于这类经验,而预构的词源即重构。重构是修改程序或软件系统内部结构的实践,以此在保留其现有行为的基础上改良设计。重构的原因有多种:方便后期增加功能、提高可维护性、提升性能。 本书作者是经验老道的软件开发人员。书中,作者运用他个人和其他众多开发人员的丰富经验,展示由其推衍而得的各项实践方针。这些方针把优秀的开发人员......一起来看看 《软件预构艺术(中文版)》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

在线进制转换器
在线进制转换器

各进制数互转换器

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具