vue项目中worker的使用及worker内引入第三方库

14,161 阅读3分钟

最近在做一个用录音输出成 MP3 的功能,在 vue 项目中用到了worker和 github 上找到的 Mp3LameEncoder.min.js 属实是被坑到了。

worker 的使用

vue.config.js 配置

  1. 首先需要安装worker-loader,并配置 vue.config.js
yarn add worker-loader -D

// vue.config.js
module.exports = {
    chainWebpack: config => {
		config.module
			.rule('worker')
			.test(/\.worker\.js$/)
			.use('worker')
			.loader('worker-loader')
            // .options({ inline: 'fallback' }) // 这个配置是个坑,不要加
	}
}

准备 worker 文件

  • 在 worker 的作用域(?)内, 没有 window,document。而是用 self,相当于 this 的一个存在,指的是 worker 这个线程内。
  • woker 有postMessage 方法 和 onmessage 属性,用来输出和监听输入
// foo.worker.js
// 用一个匿名函数自调用
;(function () {
  self.onmessage = e => {
    // e是 事件对象 MessageEvent
    // e.data是从外面传进worker的内容,假如传了 { a: 1 }
    console.log(e.data) // { a: 1 }
    /* do something */
  }

  setTimeout(() => {
    self.postMessage({ b: 1 })
  }, 3000)
})()

使用 worker

关于 worker 的更多介绍可以去看 阮一峰的关于 worker 的文章

  • worker 传值是一个拷贝的过程,大概是先串化,然后到 worker 内部再还原回来。并不是传地址值
  • 所以在 worker 中传入后,外部修改对象之类的不会改变 worker 内的数据的,可以说是一次性交易,交易完就外部就管不到了。
  • 假如传一个函数过去会怎么样呢?我尝试了一下答案是 postMessage 会报错。
/* 在需要用到worker的文件中 */
// 引入worker文件
import myWorker from 'foo.worker.js'

const worker = new myWorker()

worker.postMessage({ a: 1 })
worker.onmessage = e => {
  // e 是 worker的事件对象 MessageEvent
  // 和 onclick 这些事件对象一个概念
  // e.data, 假如传入 { b: 1 }
  console.log(e, e.data) // MessageEvent, { b: 1 }
  /* do something */
}

如此一来,简单的 worker 就实现了。

importScripts

因为需要引入处理音频流的编码方法,而在 worker 内部 是不能用 importrequire。经过一轮查找,是需要用到importScripts(xxx)

xxx 是引用文件的地址,测试了一下是不支持相对路径的。也许是可以用 http 地址,但我没试成功,不知道问题出在了哪里。如果是直接填文件名 importSCripts(a.js),坑就在这里出现了。

还记得一开始配置 vue.config.jsinline: 'fallback' 吗。意思是会将 worker 打包成 blob,默认值是 undefined,不用去设置。

一旦设置之后 vue 打包出来的 dist 放到服务器时, worker 会请求/ab48a7c5-100f-40ee-8d2c-0a2a6c568678,然后肯定请求不到,就会报错。

Uncaught DOMException: Failed to execute 'importScripts' on 'WorkerGlobalScope': The URL 'a.js' is invalid.

worker 不配置的话,importScripts 请求的地址是,后端得到的 url 是 js/a.js, 所以 vue 打包 dist 文件后,手动把 a.js 文件放进 dist/js 里面,就可以正常使用了。

一个简单的 demo,包含服务器 server,简单的把 dist 部署到了服务器,大家可以看看请求的 url。同时也可以在浏览器的 network 查看网络请求。

我把 dist 文件放了一份进服务器文件夹,里面自己放了 a.js。vue 打包的 dist 文件夹是没有 a.js 文件的,因为打包不到,所以开发时,yarn serve 是无法正常使用 importScripts 的。

  启动服务器
  cd server
  node index.js

  根目录
  yarn build

  yarn serve

注意: 如果想自己测试并重新打包的话,要在 node_modules 文件下把 .cache 文件夹删掉,不然打包不会生成 worker 的文件。