相信大家已经知道了webworker,这里就不多赘述了。
但是我发现了一个问题,就是很多文章在介绍webworker的时候,worker.js里面的内容都是写死的,然后前端页面直接获取数据。但是更多情况下,我们也不知道worker要做什么,只是希望能够借助它作为多线程的计算能力,而不阻塞主线程。那么能不能在主线程写个函数,然后交给worker去计算?于是我尝试了一下
首先是不用worker的代码
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
div {
width: 100px;
height: 100px;
background-color: red;
}
</style>
</head>
<body>
<div></div>
<script>
function fn() {
let count = 0
for (let i = 0; i < 10000000000; i++) {
count++
}
return count
}
console.log(fn())
</script>
</body>
</html>
我们可以看到,页面卡了很久,才把红色的方块渲染出来。而使用worker,把fn作为参数传过去怎样?修改代码:
js
// script
const worker = new Worker('./worker.js')
worker.postMessage(fn)
function fn() {
let count = 0
for (let i = 0; i < 10000000000; i++) {
count++
}
return count
}
worker.onmessage = ({ data }) => {
console.log(data)
}
// worker.js
onmessage = (e) => {
const fn = e.data
const data = fn()
postMessage(data)
}
但是页面就报错了
查了一下发现,原来postMessage只能传数字、字符串、布尔值、普通类型数组或普通类型对象。到这里好像没办法了,但是我想到了eval,就是把函数当成字符串传过去,再由worker用eval去执行。于是重新修改代码:
js
//html
const worker = new Worker('./worker.js')
worker.postMessage(`(${fn})()`)
function fn() {
let count = 0
for (let i = 0; i < 10000000000; i++) {
count++
}
return count
}
worker.onmessage = ({ data }) => {
console.log(data)
}
// worker.js
onmessage = (e) => {
const data = eval(e.data)
postMessage(data)
}
我们可以看到结果出来了
并且不依赖于worker.js的内容了,只把它当成一个多线程的计算工具,前端想用它来计算什么,就传什么。比如我们再添加一个函数test
js
const worker = new Worker('./worker.js')
worker.postMessage(`(${fn})()`)
function fn() {
let count = 0
for (let i = 0; i < 10000000000; i++) {
count++
}
return count
}
function test() {
let count = 0
for (let i = 0; i < 7777777777; i++) {
count++
}
return count
}
worker.postMessage(`(${test})()`)
worker.onmessage = ({ data }) => {
console.log(data)
}
完美计算出来
如果并发的任务很多,且每一个的计算量都很大,而我们只需要获取最终的结果。我们就可以写多个worker文件,比如worker1.js、worker2.js文件,相当于开启多个线程,然后把任务传入不同的worker中计算。