当前位置: 首页 > 科技观察

Web性能优化的十五个实用技巧

时间:2023-03-12 16:08:57 科技观察

JavaScript在浏览器中运行的性能可以说是开发人员面临的最严重的可用性问题。javascript的阻塞特性使这个问题变得复杂。事实上,大多数浏览器使用单个进程来处理用户界面和js脚本执行,因此一次只能做一件事。js执行过程耗时越长,浏览器等待响应的时间就越长。加载与执行1.提升加载性能1.IE8、FF、3.5、Safari4、Chrome都允许并行下载js文件,一个脚本下载资源时,不会阻塞其他脚本的下载。但是js下载还是会阻塞其他资源的下载,比如图片。虽然脚本下载不会互相影响,但是页面还是要等到所有的js代码都下载执行完了再继续。因此,仍然存在脚本阻塞问题。建议将所有js文件放在body标签的底部,减少对整个页面的影响。2、减少离页脚本文件的数量将提高页面性能:HTTP请求会带来额外的开销,所以下载一个300k的文件会比下载十个30k的文件更有效率。3、动态脚本加载技术:无论何时开始下载,文件的下载和执行都不会阻塞页面上的其他进程。functionlaodScript(url,callback){varscript=document.createElement('script');script.type='text/javascript';if(script.readyState){//iescript.onreadystatechange=function(){if(script.readyState=='loaded'||script.readyState=='complete'){script.onreadystatechange=null;callback()}}}else{//其他浏览器script.onload=function(){callback()}}script。src=url;document.getElementsByTagName('head')[0].appendChild(script);}//使用loadScript('./a.js',function(){loadScript('./b.js',function(){loadScript('./c.js',function(){console.log('loadingcomplete')})})})4.非阻塞加载类库-LABjs,使用如下://链式调用时文件一个一个下载,.wait()用于指定文件下载执行后调用的函数。$LAB.script('./a.js').script('./b.js').wait(function(){App.init();})//为了保证执行顺序,你可以这样做。这时a必须在b之前执行$LAB.script('./a.js').wait().script('./b.js').wait(function(){App.init();})2.数据访问和JS性能1.在js中,数据存储的位置对代码的整体性能有很大的影响。有四种存储数据的方式:文字、变量、数组项和对象成员。它们有各自的性能特点。2.访问文字和局部变量是最快的。相反,访问数组和对象就比较慢。3.由于局部变量存在于作用域链的开头,访问局部变量比访问跨域变量更快4.对象成员嵌套显然会影响性能,应尽量避免。5、属性和方法在原型链中越深,访问速度越慢。6、通常我们可以使用需要多次使用的对象成员和数组元素。跨域变量保存在局部变量中,提高js性能三、DOM编程1、访问DOM会影响浏览器性能,修改DOM会消耗更多的性能,因为会导致浏览器重新计算页面的几何变化。<通常的做法是减少访问DOM的次数,尽量把操作放在JS端。注意:如果在性能密集型操作中更新一段HTML,建议使用innerHTML,因为它在大多数浏览器中运行速度非常快。但对于大多数日常操作来说,差别不大,所以你应该根据可读性、稳定性、团队习惯和代码风格综合决定使用innerHTML还是createElement()。2.HTML集合优化HTML集合包含DOM节点引用的类数组对象始终连接到文档。每次需要最新的信息时,都会重复查询操作,即使只是获取集合中的元素个数。①优化1—CollToArr函数collToArr(coll){for(vari=0,a=[],len=coll.length;ip')4.重绘重排浏览器下载完页面的所有组件-html、js、css、图片等后,会解析并生成两个内部数据结构——DOM树和渲染树。DOM树和渲染树构建完成后,浏览器开始绘制页面元素(paint)。①重排条件:增加或删除可见DOM元素位置变化,元素大小变化,内容变化,页面渲染器初始化,浏览器窗口大小变化。当出现滚动条时,会触发整个页面的重新排列。重排必须重绘。5.渲染树变化的排列和刷新。但是为了优化重排过程,获取布局信息的操作会导致队列被强制刷新。offsetTop,offsetWidth...scrollTop,scrollHeight...clientTop,clientHeight...getComputedStyle()一些优化建议:将设置样式的操作和获取样式的操作分开://setstylebody.style.color='red';body.style.fontSize='24px'//读取样式letcolor=body.style.colorletfontSize=body.style.fontSize另外获取计算属性的兼容写法:functiongetComputedStyle(el){varcomputed=(document.body.currentStyle?el.currentStyle:document.defaultView.getComputedStyle(el,'');returncomputed}6.最小化重绘重排①.批量改变样式functionappendDataToEl(option){vartargetEl=option.target||document.body,createEl,data=option.data||[];//让容器远离文档流,减少重绘和重排vartargetEl_display=targetEl.style.display;targetEl.style.display='none';//*****创建Document片段以优化Dom操作****varfragment=document.createDocumentFragment();//用数据填充元素for(vari=0,max=data.length;i300){stop();}④.谨慎使用:hover如果有很多Element使用:hover,那么相应的速度会降低,CPU会增加⑤.使用事件委托(通过事件冒泡实现)减少事件处理器的数量,减少内存和处理时间;if(target.nodeName!==selector||target.className!==selector||target.id!==selector){return;}if(typeofe.preventDefault==='function'){e.preventDefault();e.stopPropagation();}else{e.returnValue=false;e.cancelBubble=true;}callback()}四、算法及流程控制1、减少循环中的属性查找和反转(可提高性能50%-60%)functiondelegation(e,selector,callback){e=e||window.event;vartarget=e.target||e.srcElement;if(target.nodeName!==selector||target.className!==selector||target.id!==selector){return;}if(typeofe.preventDefault==='function'){e.preventDefault();e.stopPropagation();}else{e.returnValue=false;e.cancelBubble=true;}callback()}2.使用Duff设备优化循环(这个方法会在后面的文章中详细介绍)3.基于函数的迭代(比基于循环的迭代慢)items.forEach(function(value,index,array){process(value);})4.通常,switch比if-else更快,但它不是最好的解决方案。五、字符串和正则表达式1、除了IE,其他浏览器都会尝试为setstring分配更多的内存,然后简单的复制第二个string到它的末尾。如果在循环中,基础字符串在最左边,可以避免重复复制逐渐变大的基础字符串2.使用[\s\S]匹配任何字符串3.去除尾随空格的常用做法:if(!String.prototype.trim){String.prototype.trim=function(){returnthis.replace(/^\s+/,'').replace(/\s\s*$/,'')}}六。快速响应的用户界面1.浏览器UI线程:用于执行javascript和更新用户界面的进程。2、在windows系统中,定时器分辨率是15毫秒,所以如果设置小于15毫秒,IE会被锁定。建议延迟的最小值为25ms。3、使用delay数组划分耗时任务:functionmultistep(steps,args,callback){vartasks=steps.concat();setTimeout(function(){vartask=tasks.shift();task.apply(null,args||[]);//调用Apply参数必须是数组if(tasks.length>0){setTimeout(arguments.callee,25);}else{callback();}},25);}4.记录代码运行时间批任务:functiontimeProcessArray(items,process,callback){vartodo=item.concat();setTimeout(function(){varstart=+newDate();do{process(todo.shift());}while(todo.length>0&&(+newDate()-start<50));if(todo.length>0){setTimeout(arguments.callee,25);}else{callback(items);}},25)}5.使用WebWorker:它引入了一个接口,可以让代码运行而无需在浏览器UI线程上花费时间。一个Worker由以下几部分组成:①一个navigator对象,包括appName、appVersion、userAgent和platform。②一个location对象,只读。③一个self对象,指向全局worker对象④一个importScripts()方法,用于加载worker使用的外部js文件⑤所有ECMAScript对象。如object、Array、Date等⑥XMLHttpRequest构造函数⑦setTimeout(),setInterval()⑧一个close()方法,可以立即停止worker运行应用场景1.编码/解码大字符串2.复杂的数学运算(包括图片,屏幕处理)3.大数组排序//worker.jsvarworker=newWorker('code.js');//接收信息worker.onmessage=function(event){console.log(event.data);}//sendDataworker.postMessage('hello');//code.js//导入其他计算代码importScripts('a.js','b.js');self.onmessage=function(event){self.postMessage('hello'+event.data);}七。ajax优化1.向服务端请求数据的五种方式:①XMLHttpRequest②动态脚本标签插入动态脚本注入③iframe④Comet(基于http长连接的服务端推送技术)⑤MultipartXHR(允许客户端从多个资源传输服务器到客户端只有一个http请求)2.简单的向服务器发送数据(beacons方法)-Beacon//唯一的缺点是接收到的响应类型有限varurl='/req.php';varparams=['step=2','time=123'];(newImage()).src=url+'?'+params.join('&');//如果数据回传给监听服务器就可以执行onload中varbeacon=newImage();beacon.src=...;beacon.onload=function(){...}beacon.onerror=function(){...}3.ajax性能缓存数据的一些建议1.在服务器上设置Expires头信息,保证浏览器缓存响应多久(需要GET请求)2.客户端将获取到的信息缓存到本地,避免再次请求8.Pr编程实践1.避免重复工作//1.延迟加载vara=(x,y)=>{if(x>4){a=0;}else{a=1;}}//需要时调用a();//2.条件预加载(适用于函数立即执行且操作频繁的场景)varb=a>0?'4':'0';2.使用Object/Arrayliterals3.使用更多的native方法9.构建和部署高性能的js应用1.jshttp压缩当web浏览器请求资源时,通常会发送一个Accept-EncodingHTTPheader来告诉Web服务器支持哪种编码转换类型。此信息主要用于压缩文档以加快下载速度,从而改善用户体验。Accept-Encoding的可用值包括:gzip、compress、deflate、identity。如果Web服务器在请求中看到这些标头,它将选择最合适的编码方法并通过Content-EncodingHTTP标头将其内容通知Web浏览器。决定。2.使用H5离线缓存3.使用内容分发网络CDN4.在页面进行性能分析//检测代码运行时间varTimer={_data:{},start:function(key){Timer._data[key]=newDate();},stop:function(key){vartime=Timer._data[key];if(time){Timer._data[key]=newDate()-time;};console.log(Timer._data[key]);returnTimer._data[key]}};10.浏览器缓存1.添加Expires头2.使用cache-controlcache-ontrol详细解释浏览器缓存机制11.压缩组件1.web客户端可以通过HTTP请求Accept-Encoding头来表示支持压缩//当browserrequests,setAccept-Encoding:gzipforthehttpheader//当web服务器响应时,为httpheader设置Content-Encoding:gzip2.压缩可以减少响应中的数据量近70%,让你可以考虑压缩html、脚本、样式、图片。12、白屏现象的原因。浏览器(如IE)在样式表下载完成后才会渲染页面,导致页面白屏。如果样式表放在页面底部,那么浏览器下载样式表的时间会比较长,所以会出现白屏,所以最好把样式表放在头部。白屏是浏览器对“无样式闪烁”的修复。如果浏览器没有使用“白屏”机制逐渐显示页面内容(如Firefox),后面加载的样式表会导致页面重绘和重新排列,会承担页面闪烁的风险。十三。css表达式使用一次性表达式(但最好避免css表达式)在使用css表达式时,执行函数会自己重写//cssp{background-color:expression(altBgcolor(this))}//jsfunctionaltBgcolor(el){el.style.backgroundColor=(newDate()).getHours()%2?"#fff":"#06c";}十四。减少DNS查找DNS缓存和TTL1.DNS查找可以被缓存以提高性能:DNS信息将保留在操作系统的DNS缓存中(MicrosoftWindows上的“DNSClient服务”,后续对主机名的请求不需要执行toomanylookups2.TTL(timetolive):这个值告诉客户端它可以将记录缓存多长时间。建议将TTL值设置为一天//客户端收到DNS记录的平均TTL只有最大TTL值的一半因为DNS解析器返回的时间是其记录的TTL的剩余时间,对于给定的主机名,每次执行DNS查找时收到的TTL值都会改变3.减少DNS查找使用Keep-Alive和更少的域名4.一般建议页面组件至少放在2个,但不要超过4个主机名下十五.避免重定向需要前后端配合统一规范页面路由。