webWorker多线程调用
1.webWorker多线程可最大程度调用cpu,调用计算机的多个核心同时工作
2.不会阻塞主线程, js线程与gui进程并行
3.计算密集型或高延迟的任务
知识点
浏览器中会存在如下这些进程
浏览器主进程: 负责协调、主控、只有一个 GPU进程:用于3D绘制,可以禁用,只有一个
第三方进程: 每种类型的插件对应一个进程,仅当使用该插件时才创建
渲染进程: 浏览器渲染进程(render进程),即通常说的浏览器内核,主要作用是:页面渲染、脚本执行、事件处理等。每一个标签页的打开都会创建一个Render进程,并且互不影响。默认的话一个标签页对应一个Render进程,但是,有时候浏览器会将多个进程合并,如打开了多个空白标签页。
此外还会存在很多线程,如:
GUI渲染线程: 主要负责渲染浏览器界面,解析HTML,CSS,构建DOM树和Render树,布局和绘制、以及回流重绘等。
JS引擎线: JS引擎线程也称为JS内核,负责处理Javascript脚本程序,解析Javascript脚本,运行代码。
事件触发线程: 事件触发线程归属于浏览器,而不是属于JS引擎,JS引擎处理的事务过多,需要浏览器另开线程来进行协助
定时器触发线程: 即setInterval与setTimeout所在线程
异步http请求线程: XMLHttpRequest连接后通过浏览器新开一个线程请求 worker线程其中GUI渲染线程和JS引擎线程是互斥的,他们会共用渲染进程,当JS引擎执行时,GUI线程就会被挂起(相当于被冻结了),GUI更新会被保存在一个队列中等到JS引擎空闲时,才会被执行。
.
举一个简单的小例子,比如咱们通过requestAnimationFrame这个api每16.6ms获取一次时间,并且渲染。当JS引擎线程繁忙的时候,GUI线程就会被挂起,即不会更新咱们页面上的时间,从而导致卡顿的现象。
应用场景
1.大文件分片上传
2.excel大文件导出
3.图片批量压缩
4.canvas绘制
5.音视频渲染
使用方法
worker.postMessage: 向 worker 的内部作用域发送一个消息,消息可由任何 JavaScript 对象组成
worker.terminate: 立即终止 worker。该方法并不会等待 worker 去完成它剩余的操作;worker 将会被立刻停止
worker.onmessage: 当 worker 的父级接收到来自其 worker 的消息时,会在 Worker 对象上触发message 事件
worker.onerror: 当 worker 出现运行中错误时,它的 onerror事件处理函数会被调用。它会收到一个扩展了 ErrorEvent 接口的名为 error 的事件
代码示例
Html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>web worker</title>
</head>
<script>
const number = 20 // 运行次数
// 多线程测试
function workerTest() {
console.log('%c 开始多线程测试 ', 'color:#fff; background:#00897b ')
const workerList = []
for (let i = 0; i < number; i++) {
const workerItem = new Promise((resolve, reject) => {
const myWorker = new Worker('./worker.js')
myWorker.postMessage({
function: 'fb',
data: 43
})
myWorker.onmessage = (e) => {
resolve(e.data)
// 关闭worker线程
myWorker.terminate()
}
})
workerList.push(workerItem)
}
console.time('worker多线程执行时间')
Promise.all(workerList).then(res => {
console.log(res)
console.timeEnd('worker多线程执行时间')
})
}
function singleTest() {
console.log('%c 开始单线程测试 ', 'color:#fff; background:#00897b ')
function fb(n) {
if (n === 1 || n === 2) {
return 1;
}
return fb(n - 1) + fb(n - 2)
}
console.time('单线程执行时间')
for (let i = 0; i < number; i++) {
const res = fb(43)
console.log({
data: res,
name: 'single test'
})
}
console.timeEnd('单线程执行时间')
}
</script>
<body>
<button onclick="singleTest()">单线程测试</button>
<button onclick="workerTest()">多线程测试</button>
</body>
</html>
worker.js
// 方法对象
const funcObj = {
fb: (n) => {
if (n === 1 || n === 2) {
return 1;
}
return funcObj.fb(n - 1) + funcObj.fb(n - 2);
},
};
// onmessage事件
onmessage = function (e) {
const { data } = e;
const res = funcObj[data.function](data.data);
// 将获取的数据通过postMessage发送到主线程
self.postMessage({
data: res,
name: "worker test",
});
self.close();
};
查询客户端线程数
window.navigator.hardwareConcurrency