ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、视频、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
# Worker > 使用 `Worker` 可以开启、调度其他线程处理一些耗时任务。但是它只兼容现代浏览器,所以,使用时需要先看系统部署的环境是否支持 [Worker 兼容性查询](https://caniuse.com/?search=Worker) 参考:[MDN-关于Worker](https://developer.mozilla.org/zh-CN/docs/Web/API/Worker) ## Worker url 根据文档所述,`Worker` 创建时支持 `blob url`。所以在 `Vue2` 项目中可以这样引入一个 `assets` 目录下的 `worker.js` (不推荐用这种写法)。 ```javascript // worker.js export default function () { self.addEventListener('message', function (e) { console.log('worker 收到 message', e.data) self.postMessage("hello") }, false) } ``` ```vue // test.vue <script> import workerScript from '@/assets/worker.js' export default { mounted() { const blob = new Blob(`(${workerScript.toString()})()`, { type: 'text/javascript' }) const bloburl = URL.createObjectURL(blob) const worker = new Worker(bloburl) worker.postMessage({ type: 'test', data: 'hello' }) worker.onmessage = (eve) => { console.log('收到 worker 发送的消息', eve.data) } } } </script> ``` ## worker-loader 如果你使用的是 `Webpack` 项目,引入 `assets`目录下的 `worker` 文件时,用 `loader` 处理会更符合需求。毕竟大多时候,我们都需要在 `worker` 中引入其他包,来处理一些复杂逻辑(例如:用 `spark-md5` 计算文件 `hash` ) ```js // vue.config.js const { defineConfig } = require('@vue/cli-service') module.exports = defineConfig({ transpileDependencies: true, devServer: { open: true }, chainWebpack: config => { // 这是我的 /worker.js 文件,需要按需调整 config.module.rule('worker').test(/[\\/]worker\.js$/).use('worker-loader').loader('worker-loader').options({ inline: 'no-fallback' }) } }) ``` ```javascript // worker.js 不再需要导出 self.addEventListener('message', function (e) { console.log('worker 收到 message', e.data) self.postMessage("hello") }, false) ``` 在组件中使用 ```vue // test.vue <script> import WorkerTest from '@/assets/worker?worker&url' export default { mounted() { const worker = new WorkerTest() worker.postMessage({ type: 'test', data: 'hello' }) worker.onmessage = (eve) => { console.log('收到 worker 发送的消息', eve.data) } } } </script> ``` ## 优化 ```javascript // utils.js /** * 源于数据库连接池的概念,用于管理多 Worker 调度问题 */ class WorkerPool { constructor(maxWorkers = 2) { this.workers = [] this.running = 0 this.maxWorkers = maxWorkers } /** * * @param {() => Worker} createWorkerFunc * @returns { Promise<{ worker: Worker, release: () => void }> } */ addWorker(createWorkerFunc) { return new Promise((resolve, reject) => { this.workers.push({ resolve, reject, createWorkerFunc }) this.run() }) } run() { while (this.running < this.maxWorkers && this.workers.length > 0) { const { resolve, reject, createWorkerFunc } = this.workers.shift() try { const worker = createWorkerFunc() const release = () => { worker.terminate() this.running-- this.run() } resolve({ worker, release }) this.running++ } catch (error) { reject(error) } } } } export const MAX_WORKERS = navigator.hardwareConcurrency || 2 export const workerPool = new WorkerPool(MAX_WORKERS) ``` 在组件中使用 `workerPool` ```vue // test.vue <script> import WorkerTest from '@/assets/worker?worker&url' import { MAX_WORKERS, workerPool } from '@/utils' export default { mounted() { const worker = new WorkerTest() worker.postMessage({ type: 'test', data: 'hello' }) worker.onmessage = (eve) => { console.log('收到 worker 发送的消息', eve.data) } for (let i = 0; i < MAX_WORKERS; i++) { workerPool.addWorker(() => new Worker()).then(({ worker, release }) => { worker.postMessage("hello") worker.onmessage = e => { // 在 worker 使用完后释放资源 release() } }) } } } </script> ```