练习中……
参考:
Web Worker 有以下几个使用注意点。
同源限制、DOM限制、通信限制、脚本限制、文件限制
(1) 发送消息
主线程:worker.postMessage();
子线程:self.postMessage()
(2)接收消息
主线程:worker.onmessage(); // addEventListener(‘message’)
子线程:self.onmessage()
(3)监听异常
主线程:worker.onerror();
子线程:self.onerror()
(4)销毁方法
主线程:worker.terminate();
子线程:self.close()
(5)加载脚本(worker内部加载其他脚本)
importScripts(‘one.js’, ‘two.js’)
第二个参数是可选的配置对象,可以指定 type、credentials、name 三个属性
let worker = new Worker(new URL('work.js', import.meta.url), /* @vite-ignore */{
name: file.name
})
把需要的库的min.js文件拿出来引入
self.importScripts("spark-md5.min.js") // 与worker.js文件同级
let worker = new Worker(new URL('work.js', import.meta.url), /* @vite-ignore */{ name: file.uid })
let workerFile = file
worker.postMessage(workerFile, [workerFile])
没搞懂Transferable Objects到底咋用(但反正是传过去了,应该要用ArrayBuffer格式的)……
vue文件
let reader = new FileReader()
reader.readAsArrayBuffer(file) //
reader.onload = (e)=> {
let worker = new Worker(new URL('work.js', import.meta.url), /* @vite-ignore */{ name: file.name
})
let buffer = e.target.result
let workerFile = {
buffer,
name: file.name,
uid: file.uid
}
worker.postMessage(workerFile, [workerFile.buffer]) // 在这之后再打印file里边的属性是找不到的,因为该文件已经转移了
worker.onmessage = function (e) {
console.log(e)
}
}
work.js
var self = this
self.onmessage = async val => {
const { data } = val
let file = new File([data.buffer], data.name) // 因为接下来要用到File文件,所以这个地方要转成File对象
// 返回数据给调用者
// postMessage('接收到了')
}
self.importScripts('../../api/imageManage/uploadImage.js')
从放弃到坚持放弃,使用vite的方式会成功通信(只是打包后会报Uncaught TypeError: Cannot read properties of undefined (reading: ‘importScripts’),跟打包有关的我就不懂了。不知道项目配置不一样会不会报此错误):
文件目录:
roleList.vue代码:
<script setup>
const worker = new Worker(new URL('./worker.js', import.meta.url)) // 此方式在生产环境可能会导致报错
worker.postMessage('aaaaaaa')
worker.onmessage = e => {
console.log('来自worker的数据:' + e.data)
}
</script>
worker.js代码:
self.importScripts('spark-md5') //
self.onmessage = function (e) { //监听主线程发过来的消息
console.log('我是worker接收到的数据:' + e.data);
let sum = 0;
self.postMessage(sum); // 将信息发送到主线程上
}
生产环境中不报错的:
import ImageWorker from "./work.js?worker" // 此方式引入,解决生产环境的报错
const worker = new Worker()
worker.postMessage('aaaaaaa')
worker.onmessage = e => {
console.log('来自worker的数据:' + e.data)
}
</script>
worker.js代码:
import SparkMD5 from 'spark-md5' //
self.onmessage = function (e) { //监听主线程发过来的消息
console.log('我是worker接收到的数据:' + e.data);
let sum = 0;
self.postMessage(sum); // 将信息发送到主线程上
}```
## worker中的请求
因为worker中好像只能使用XMLHttpRequest和fetch,且没有办法引入项目中的api文件(可能是自己没找到合适的方法)。需要在worker.js中重新写一边请求路径。但是不同环境下的ip不一致,没办法写死,遂写了个demo如下:
```javascript
vue文件:
let workerFile = {
metaEnv: import.meta.env.VITE_APP_BASE_API, // 每次都传ip及token
token: 'Bearer ' + getToken(),
buffer,
name: file.name,
uid: file.uid,
fileTableIndex
}
worker.postMessage(workerFile, [workerFile.buffer])
worker.js
self.metaEnv = null
self.token = null
self.baseURL = null
self.fetchRequest = async (url, data) => {
self.baseURL =
location.protocol +
'//' +
location.hostname +
':' +
location.port +
self.metaEnv // 从roleList.vue中通信传过来的
const headers = { Authorization: self.token } // 设置token
if (!(data instanceof FormData)) {
headers['Content-Type'] = 'application/json;charset=utf-8' // 不是formData格式的数据用'application/json;charset=utf-8',formData好像不用特意设置content-type
}
return new Promise((resolve, reject) => {
fetch(self.baseURL + url, {
method: 'post',
body: data instanceof FormData ? data : JSON.stringify(data),// 如果是formData格式直接把data传过去,否则转化一下
headers
})
.then(res => res.json()) // => 为了获取 JSON 的内容,我们需要使用 json() 方法(该方法返回一个将响应 body 解析成 JSON 的 promise)
.then(res => {
resolve(res)
})
.catch(err => {
reject(err)
})
})
}