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

Web性能优化的15个实用技巧_0

时间:2023-03-15 19:27:42 科技观察

JavaScript在浏览器中运行的性能可以说是开发人员面临的最严重的可用性问题。javascript的阻塞特性使这个问题变得复杂。事实上,大多数浏览器使用单个进程来处理用户界面和js脚本执行,因此一次只能做一件事。js执行过程耗时越长,浏览器等待响应的时间就越长。一、提高加载性能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='文本/javascript';if(script.readyState){//即script.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();})二、数据访问与JS性能1、在js中,数据存放的位置会影响整体代码性能有重大影响有4种存储数据的方式:文字、变量、数组项和对象成员。它们有各自的性能特点。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()一些优化建议:将设置样式的操作和获取样式的操作分开://设置样式body.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.尽量减少重绘和重排①.批量改变样式/*使用cssText*/el.style.cssText='border-left:1px;border-right:2px;padding:20px';②.dom批量修改优化方案-使元素脱离文档流-应用多次修改-带回元素到文档函数appendDataToEl(option){vartargetEl=option.target||document.body,createEl,数据=选项。数据||[];//让容器远离文档流,减少重绘和重新排列vartargetEl_display=targetEl.style.display;targetEl.style.display='无';//*****创建文档片段以优化Dom操作****varfragment=document.createDocumentFragment();//用数据填充元素for(vari=0,max=data.length;i300){stop();}④慎用:hover如果有lot元素使用:hover,那么相应的速度会降低,CPU会增加。⑤使用事件委托(通过事件冒泡实现)减少事件处理器的数量,减少内存和处理时间functiondelegation(e,selector,callback){e=e||窗口事件;var目标=e.target||e.src元素;if(target.nodeName!==选择器||target.className!==选择器||target.id!==选择器){return;}if(typeofe.preventDefault==='function'){e.preventDefault();e.stopPropagation();}else{e.returnValue=false;e.cancelBubble=true;}callback()}4.算法和流程控制1.减少属性查找和反向(可以提高50%-60%的性能)//forloopfor(vari=item.length;i--){process(item[i]);}//while循环varj=item.length;while(j--){process(item[i]);}2.使用Duff设备优化循环(此方法将在在后面的文章中详细介绍)3.基于函数的迭代(比基于循环的迭代慢)项。forEach(function(value,index,array){process(value);})4.通常,switch比if-else更快,但它不是最佳解决方案。五、字符串和正则表达式1、除了IE,其他浏览器都会尝试为表达式左边的字符串分配更多的内存,然后简单地把第二个字符串复制到它的末尾。如果在一个循环中,基本字符串在最左边,它将起作用。避免重复复制逐渐变大的基本字符串。2.使用[\s\S]匹配任意字符串3.去除尾随空格的常用做法:if(!String.prototype.trim){String.prototype.trim=function(){returnthis.replace(/^\s+/,'').replace(/\s\s*$/,'')}}6.快速响应的用户界面1.浏览器UI线程:用于执行javascript和更新用户界面的进程。2、在windows系统中,定时器分辨率是15毫秒,所以如果设置小于15毫秒,IE会被锁定。建议最小延迟值为25ms。3.用延迟数组拆分耗时任务: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。②一个位置对象,只读。③一个self对象指向全局worker对象。④一个importScripts()方法,用于加载worker使用的外部js文件。⑤所有ECMAScript对象。如object、Array、Date等。⑥XMLHttpRequest的构造函数。⑦setTimeout()、setInterval()。⑧一个close()方法,可以立即停止worker的运行。应用场景编码/解码大字符串复杂数学运算(包括图像、视频画面处理)大数组排序//worker.jsvarworker=newWorker('code.js');//接收信息worker.onmessage=function(event){console.log(event.data);}//发送数据worker.postMessage('hello');//code.js//导入其他计算代码importScripts('a.js','b.js');self.onmessage=function(event){self.postMessage('hello'+event.data);}七、ajax优化1.向服务器请求数据的五种方式:①XMLHttpRequest②动态脚本标签插入动态脚本注入③iframes④Comet(基于http长连接的服务端推送技术)⑤MultipartXHR(允许客户端只用一次http请求,就可以将服务端的多个资源传输到客户端)2.简单的向服务端发送数据(beacons方式)——标记//唯一的缺点是收到的响应类型有限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性能缓存数据的一些建议在服务器端设置Expires头信息,保证浏览器缓存响应的时长(必须是GET请求)client端将获取到的信息缓存到本地,避免再次请求八、编程实践1.避免重复工作//1.懒加载vara=(x,y)=>{if(x>4){一=0;}否则{a=1;}}//需要使用Calla()whenused;//2.条件预加载(适用于函数立即执行且操作频繁的场景)varb=a>0?'4':'0';2.使用Object/Arrayliterals三.九、构建和部署高性能js应用1.jshttp压缩当web浏览器请求资源时,通常会发送一个Accept-EncodingHTTP头来告诉web服务器是哪种编码类型conversionitsupports此信息主要用于压缩文件以加快下载速度,从而改善用户体验。Accept-Encoding的可用值包括:gzip、compress、deflate、identity。如果Web服务器在请求中看到这些标头,它将选择最合适的编码方法并通过Content-EncodingHTTP标头将其内容通知Web浏览器。决定。2.使用H5离线缓存3.使用内容分发网络CDN4.对页面进行性能分析//检测代码运行时间varTimer={_data:{},start:function(key){Timer._data[key]=新日期();},停止:function(key){vartime=Timer._data[key];if(time){Timer._data[key]=newDate()-时间;};console.log(Timer._data[key]);返回Timer._data[key]}};10.浏览器缓存1.添加Expiresheader2.使用cache-controlcache-ontrol详细解释浏览器缓存机制11.压缩组件1.web客户端可以通过http请求中的Accept-Encodingheader表示是否支持压缩//当浏览器请求时,为httpheader设置Accept-Encoding:gzip//当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查找可以Cache来提高性能:DNS信息会保留在操作系统的DNS缓存中(微软的“DNSClientService”Windows,以及后续对主机名的请求不需要进行过多的查找。2.TTL(timetolive):这个值告诉客户端这条记录可以缓存多长时间,建议将TTL值设置为1day//客户端收到DNS记录的平均TTL仅为最大TTL值的一半,因为DNS解析器返回其记录的TTL的剩余时间Time,对于给定的主机名,每次收到的TTL值都会发生变化进行DNS查找3.通过使用Keep-Alive和更少的域名减少DNS查找4.一般建议页面组件单独放置至少2个,但不超过4个主机名复制代码十五,到避免重定向需要前后端配合才能统一ly标准化页面路由。