不会webworker,你做什么性能优化??
点击关注公众号,“技术干货”及时达!
前言本来这篇文章是打算写我之前「那个迭代」的「首屏优化」的,但是我做的那些优化,前几天上了生产,效果「并不如意」,因为生产环境不能随便动,我只能在灰度环境上测试,但是灰度测试后确实是比之前好的。那篇文章我也写了大半了,过几天发出来大家指点一下。然后我最近看了评论想着使用webworker去优化一下我那坨列表,然后我之前也没用过,最近也研究了一下,所以这篇文章就给大家分享一下webworker怎么用。其实挺简单的,但是遇到了一些坑!希望大家使用的时候能注意一下。
什么是web worker??mdn的链接 https://developer.mozilla.org/zh-CN/docs/Web/API/Worker/Worker
?webworker是html5的一个api,它的作用就是新开一个线程去做一些操作,因为这个线程并不会阻塞主线程,所以可以去提高网页的性能。其实可以把他「当成一个函数」,传参进行计算得到你想要经过一些代码处理的东西。
Demo这里就以计算「计算斐波那契数列」为例子去给大家演示。
「主线程脚本(index.html)」
在主线程中 「new」一个worker对象,传参的是一个js脚本路径,「不能传其他类型的文本」,也必须是「同源」的。然后通过message事件和postmessage进行通信即可。
!DOCTYPEhtml
htmllang="en"
head
metacharset="UTF-8"
titledemo/title
/head
body
buttononclick="startCalculation()"斐波那契数列/button
pid="result"/p
script
functionstartCalculation(){
//创建一个WebWorker对象,指定worker.js作为工作线程的脚本
constworker=newWorker('worker.js');
worker.postMessage(20)
//监听工作线程发送的消息
worker.onmessage=function(event){
document.getElementById('result').innerHTML='斐波那契数列的第20项是:'+event.data;
//通知关闭线程
worker.postMessage('close')
}
/script
/body
/html
「工作线程(work.js)」
这里主要的点是「self」,在工作线程中的self就相当于「主线程的window」,也就是window中很多东西在self中也能使用。但是工作线程是没有去「获取dom的权限」的,所以他不能也不建议去操作dom。然后就是通过message和postMessage去通信。
//计算斐波那契数列的函数
functionfeibo(n){
if(n===0||n===1){
return
}
returnfeibo(n-1)+feibo(n-2);
}
//计算斐波那契数列的第10项并发送结果给主线程
self.onmessage=function(e){
console.log(e.data);
if(e.data=='close'){
//关闭线程
self.close()
return
}
constdata=feibo(e.data);
self.postMessage(data);
};
方法属性selfself是对工作线程自身全局对象的引用。类似于浏览器主线程中的window对象,要注意的self不能访问 DOM 相关内容
postmessge和message当主线程使用worker.postMessage发送消息时,工作线程中的message事件处理函数就会被触发。当工作线程使用worker.postMessage发送消息时,主线程中的message事件处理函数就会被触发。所以就是用来通信的
importScripts用于在工作线程中加载外部脚本。可以同时加载多个脚本,并且脚本会按照它们在importScripts函数参数中的顺序「依次加载」,不过我感觉这个方法应该很少用。
terminate(在「主」线程中使用)worker.terminate();
close (在「工作」线程中使用)self.colse();
是吧。其实webworker就这么点东西,就是相当一个「装机师傅」,你把主板,cpu,显卡,内存,风扇...给他,师傅就可以还给你一台主机。然后我在用的时候就发现会有一些「坑」,就会导致出现bug。
坑1:postMessage不知道大家知不知道,postMessage是一种「异步通信」。什么叫异步通信呢。就是我给你通知了,但是我不会去等你执行代码,我继续执行我的代码。大家可以用上面的demo试一下。我一开始以为是和我们vue的组件自定义事件通信那样,是「同步通信」的。其实应该很多人都不知道这个是同步通信的,这个很重要的,工作中不注意这个时机,就会导致bug,我记得我在面试的时候也被问到过。我下面写了个vue3的自定义通信的小demo,然后在自定义事件中写了for循环阻塞5秒钟,大家可以复制跑一下看看。
parent.vue
template
Child@chageFn="chageFn"/Child
/template
scriptsetup
importChildfrom"./child.vue";
constchageFn=()={
conststart=Date.now();
constwaitTime=5000;//5秒,单位是毫秒
for(leti=0;Date.now()-startwaitTime;i++){
}
console.log("5秒时间已过,继续执行后续代码");
};
/script
stylelang="scss"scoped/style
child.vue
template
button@click="clickFn"点击我/button
/template
scriptsetup
import{defineEmits}from"vue";
constemit=defineEmits(["chageFn"]);
constclickFn=()={
emit("chageFn");
console.log("1");
};
/script
stylelang="scss"scoped/style
当我们点击的时候就可以发现,是「在五秒后打印1」,并不会立即打印1,但如果是postMessage通信是会立即打印1的。然后这个同步通信并不是说一定会等自定义函数执行完才会走后面的代码,如果这个自定义函数中是异步代码,是会先打印1的,就是正常的「事件循环」机制,大家也可以试试。
坑2:序列化和反序列化postMessage在进行通信时会对数据进行「序列化」的,在message事件接收数据是会「反序列」的,啥意思呢,就是类似于JSON.parse和JSON.stringify,这两个api就是将js的数据类型转化成JSON格式的数据,但是postMessage并不是转化成JSON格式,它是一种「结构化克隆算法」,具体我也不清楚。他们的共同点都是不能转化函数,JSON.stringify是会将函数变成undefind,postMessage是报错。
!DOCTYPEhtml
htmllang="en"
head
metacharset="UTF-8"
metaname="viewport"content="width=device-width,initial-scale=1.0"
titleWebWorkerFunctionandCircularReferenceExample/title
/head
body
script
constfn=()={
console.log(1)
}
console.log(JSON.stringify(fn))//undefind
constworker=newWorker('worker.js')
worker.postMessage(fn)//报错
/script
/body
/html
坑3:如何正确的去通信以及正确的去关闭工作线程当我们使用webworker的时候不可能说每使用一次就new一次webwoker,而是每次都是使用这一个线程进行处理。然后可能会导致什么问题呢?还是那个装机师傅的例子,「有两个人同时去找这个师傅装机,装完了师傅不知道这两个机子分别是谁的」。那师傅肯定没有这么笨,他肯定会贴个标签说这个是他的,那个是她的。所以,当我们通信的时候就需要去规定通信的格式。比如下面这样,当主线程给工作线程通信的时候,传一个id字段实现唯一性,当工作线程回复的时候也带上这个字段,大家具体情况具体分析。
constparams={
id:"1",
params:{
}
}
constresponse={
id:"1",
data:{
}
}
关闭工作线程是有两种方式的,一种是「主线程去关闭」,另一种是「工作线程自己关闭」。如果协调不好的话就可能会导致工作线程的代码并没有执行完成就关闭了,然后就会引出很多问题。不过这个我倒是没遇到过hhh,其实我觉得可以去统一一下关闭的地方。比如,「统一由主线程去关闭」,当工作线程想关闭的时候,去通过postmessage去通知主线程去关闭。
总结我觉得webworker其实大部分前端应该是很少用到的,反正我是第一次用。不过也并不是很难,稍微看一下就能学会,就能使用在工作上了。这应该也只会在「性能优化」的时候去使用,毕竟在大多数情况下封装函数就行了,谁会想着新开一个线程去处理,麻烦死了。只能说,技多不压身,学不死就往死里学!
点击关注公众号,“技术干货”及时达!
阅读原文
网站开发网络凭借多年的网站建设经验,坚持以“帮助中小企业实现网络营销化”为宗旨,累计为4000多家客户提供品质建站服务,得到了客户的一致好评。如果您有网站建设、网站改版、域名注册、主机空间、手机网站建设、网站备案等方面的需求...
请立即点击咨询我们或拨打咨询热线:13245491521 13245491521 ,我们会详细为你一一解答你心中的疑难。 项目经理在线