WebWorker:浏览器的 "异步执行"
介绍:https://developer.mozilla.org/zh-CN/docs/Web/API/Web_Workers_API
WebWorker与异步任务
在一般的异步任务如ajax, 计时器等等,都会交给浏览器相应的异步模块去执行,在执行过程中不会阻塞主线程的操作。那么当我们需要做一些自定义复杂的计算时(没有现成的web api),如果直接放在主线程执行,会阻塞整个页面,无法进行别的操作。这时候就可以使用webworker开辟一个子线程,让计算在子线程中执行,而不会影响到主线程。
可以在Worker线程中做什么?
- 网络操作(Ajax、Socket)
- 计时器操作
- 访问某些重要全局变量及功能的复本
- 做复杂度较高的计算
注:Worker线程中不能操作DOM、不能使用全局变量/对象/函数。
1. 用来进行计算
父进程
let worker = new Worker("/static/worker.js");
//发送消息到worker.js中
worker.postMessage({
type: "all",
id: 2
});
// 接收worker的消息
worker.addEventListener("message", function (e) {
console.log("接收消息", e.data.content); //sum:101
})
子进程:这里做个简单的计算
// worker.js
self.addEventListener('message',function(event){
let arr = [1,2,3,4,4,5,6,7,8,5,5,3,2,2,4,5,6,7,5,3,3,5,6,];
let sum = arr.reduce((pre,cur)=>{
return pre+cur
});
self.postMessage({
type:'all',
content:sum
});
});
2.用来发送ajax请求
当页面中存在很多图片需要加载时,经常会用到懒加载。但也有特定的需求需要一次性加载所有图片,这时候可以用子线程来加载
worker.js
(function(){
let arr = ['http://img3.imgtn.bdimg.com/it/u=3307014006,766424055&fm=15&gp=0.jpg',
'https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg',
'https://fuss10.elemecdn.com/1/34/19aa98b1fcb2781c4fba33d850549jpeg.jpeg',
'https://fuss10.elemecdn.com/0/6f/e35ff375812e6b0020b6b4e8f9583jpeg.jpeg',
'https://fuss10.elemecdn.com/9/bb/e27858e973f5d7d3904835f46abbdjpeg.jpeg',
'https://fuss10.elemecdn.com/d/e6/c4d93a3805b3ce3f323f7974e6f78jpeg.jpeg',
'https://fuss10.elemecdn.com/3/28/bbf893f792f03a54408b3b7a7ebf0jpeg.jpeg',
'https://fuss10.elemecdn.com/2/11/6535bcfb26e4c79b48ddde44f4b6fjpeg.jpeg'];
for (let i = 0, len = arr.length; i < len; i++) {
let req = new XMLHttpRequest();
req.open('GET', arr[i], true);
req.responseType = "blob";
//req.setRequestHeader("client_type", "DESKTOP_WEB");
req.onreadystatechange = () => {
if (req.readyState == 4) {
postMessage(req.response);
}
};
req.send(null);
}
})();
主线程:
let w = new Worker("/src/js/worker/worker.js");
w.onmessage = function (event) {
let img = document.createElement("img");
img.style.width = '100%';
img.src = window.URL.createObjectURL(event.data); // 把图片blob对象转变成url
document.querySelector('#result').appendChild(img)
console.log(event.data);
};
w.onerror = function(e){
// e.currentTarget.terminate();
console.log('erro: ' + e.message);
};
Vue-worker
Vue-Worker把复杂的web worker用Promise封装起来,提供一套非常简明的api接口
安装
npm i -S vue-worker
注册
import VueWorker from 'vue-worker'
Vue.use(VueWorker)
使用 :结合create([...actions])和postMessage使用,可以在create钩子函数中定义每个message对应哪个处理函数,然后直接使用worker.postMessage来调用并传参。子线程中把结果return 出来,父线程用then来触发回调。
//父线程
create(){
this.worker = this.$worker.create(
[
{
message: 'calc',
func:worker.calcSomeThing
},
//{...}
]);
}
methods:{
docalc(){
let data = [1,2,3,4,5,6,5];
this.worker.postMessage('calc', [data]).then(res =>{
console.log(res); // sum is: 26
})
}
}
// worker.js
function calcSomeThing(arr){
return 'sum is:'+arr.reduce((pre,cur)=>{
return pre+cur
})
}
run方法结合了create和postMessage,调用更为方便,但run是一次性的,跑完这次,worker线程就会被关掉。
this.worker = this.$worker.run(worker.calcSomeThing).then(res=>{
console.log(res) // sum is:55
}).catch(e=>{
console.log(e)
})
// worker.js
function calcSomeThing(){
let arr = [1,2,3,4,5,6,7,8,9,10];
return 'sum is:'+arr.reduce((pre,cur)=>{
return pre+cur
})
}
export default {
calcSomeThing
}