当前位置: 首页 > 后端技术 > Node.js

Js基础(五)——前端性能优化总结

时间:2023-04-03 10:09:04 Node.js

资源优化缓存前端性能优化总结最好的资源优化就是不加载资源。缓存也是最有效的优化手段。老实说,虽然客户端缓存发生在浏览器端,但是缓存主要是由服务器端控制的,和我们的前端关系不大。但是还是有必要了解一下。缓存包括服务器端缓存和客户端缓存。本文只讨论客户端缓存。所谓客户端缓存,主要是http缓存。HTTP缓存主要分为强制缓存和协商缓存。Expires的强制缓存(http1.0)Expires在http1.0中用于强制缓存。Exprires的值是服务器返回数据的过期时间。当再次请求时的请求时间小于返回时间时,将直接使用缓存的数据。但是,由于服务器时间和客户端时间之间可能存在差异,这也会导致缓存命中错误。Cache-ControlCache-Control有很多属性,不同的属性代表不同的含义。private:客户端可以缓存public:客户端和代理服务器都可以缓存都会缓存。协商缓存当浏览器第一次请求数据时,服务器将缓存标识符和数据响应给客户端,客户端将它们备份在缓存中。再次请求时,客户端会将缓存中的标识发送给服务端,服务端根据标识进行判断。如果不无效则返回一个304状态码,浏览器拿到这个状态码后就可以直接使用缓存的数据了。Last-Modified服务器响应请求时,会告诉浏览器资源的最后修改时间if-Modified-Since当浏览器再次请求服务器时,请求头中会包含该字段,后面跟上Last-Modified在缓存中获取(最终更改时间)。当服务器收到这个带有if-Modified-Since的请求头时,它会将它与所请求资源的最后修改时间进行比较。如果大于请求资源的最后修改时间,则返回304,浏览器从缓存中获取资源。如果小于请求资源的最后修改时间,则返回200,返回最新的资源。浏览器从服务器获取最新的资源并缓存起来。etag是服务器生成的每个资源的唯一标识字符串If-None-Match再次请求服务器时,浏览器的请求报文头中会包含该字段,后面的值就是在缓存中获取到的标识。服务端收到第二条消息后,发现将If-None-Match与请求资源的唯一标识进行比较。如果相同,则表示资源未被修改,返回304,浏览器从缓存中获取资源,如果不同,则表示资源已被修改,返回200,返回最新的resource,浏览器从服务器获取最新的资源,并缓存起来。Last-Modified和ETag可以一起使用。服务器会先验证ETag。如果一致,就会继续比较Last-Modified,最后决定是否返回304。如果使用前端打包工具,可以在打包文件的时候给文件加上版本号或者hash值,以及还可以区分资源是否过期。减少http请求使用CDN托管静态资源可以使用gulp、webpack等打包工具合并压缩js、css等文件图片的延迟加载和按需加载,滚动到可见区域时加载小图片图片和基本没有修改过的图片使用base64编码传输。不要滥用base64。即使是小图片,经过base64编码后也会生成很长的字符串。如果滥用base64,会适得其反。精灵图用于基本不会变化的图片。会导致整个精灵贴图重新生成,乱用会适得其反。减少http请求资源量。使用webpack、gulp等工具压缩资源。在服务器端开启gzip压缩(压缩率很可观,一般在30%以上)。打包工具有用的话,打包优化一定要做好,公共资源,第三方提取代码,不需要打包的库...渲染优化看过前面js运行机制的应该都知道是怎么回事从浏览器输入url到屏幕上出现的页面(tcp握手,dns分析等不在识别范围)。FPS16ms最好小于10ms。Googledevtool检查帧速率。如果浏览器FPS达到60,会显得更流畅。大多数显示器的刷新率为60Hz,浏览器会以这个频率自动刷新动画。按照FPS等于60计算,一帧的平均时间为1000ms/60=16.7ms,所以每次渲染时间不能超过16ms,如果超过这个时间,就会出现丢帧卡顿的情况。在chrome浏览器的开发者工具中的Timeline中可以查看刷新率,可以查看所有帧率的耗时和某帧的执行情况。Timeline使用教程:https://segmentfault.com/a/11...为了保证正常的FPS,一些渲染性能的优化还是很有必要的。以下是渲染优化的所有策略。尝试使用css3制作动画。众所周知,css的性能比js快,所以可以用css,尽量不要用js,避免使用setTimeout或setInterval,动画或高频Dom操作尽量用requestAnimationFrame。因为setTimeout和setInterval不能保证回调函数的执行时机,很可能在帧结束时执行,导致丢帧,但是requestAnimationFrame可以保证回调函数在每一帧动画开始时执行.requestAnimationFrame的中文MDN地址:https://developer.mozilla.org...使用WebWorkers进行复杂的计算操作。如果你需要复杂的数据操作,比如遍历和求和单个元素的数组,那么WebWorkers是完美的。WebWorkers允许JavaScript脚本在后台线程中运行(类似于创建子线程),后台线程不会影响主线程中的页面。但是,使用WebWorker创建的线程无法操作DOM树。关于WebWorkers的更多信息可以查看MDN详细解释:https://developer.mozilla.org...css放在最前面,js放在最后面。看过前面js运行机制的应该都知道页面渲染是怎样一个过程,这里不再赘述。将css放在最前面,可以避免生成html树后重新布局的闪屏现象。js一般对页面的影响比较大,一般在最后执行。事件防抖(debounce)和节流(throttle)针对高频触发事件(mousemove、scroll)等事件。如果不加以控制,短时间内就会触发很多事件。函数防抖是指在频繁触发的情况下,在空闲时间足够的情况下,只执行一次代码。场景:注册时的邮箱输入框,随着用户的输入,实时判断邮箱格式是否正确。当触发第一个输入事件时,设置时序:800ms后执行校验。如果只过了100ms,还没有执行上次计时,此时清零计时,重新计时800ms。直到最后一次输入,没有后续输入,最后一次输入的计时结束,最后执行校验代码。constfilter=/^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;$("#email").on("keyup",checkEmail());functioncheckEmail(){让定时器=null;返回函数(){clearTimeout(timer);timer=setTimeout(function(){console.log('执行检查');},800);}}函数节流是指js方法在一定时间内只运行一次。也就是说,原本应该每秒执行100次的操作变成了每秒执行10次。场景:功能节流应用的实际场景,大部分会在监听页面元素的滚动事件时使用。varcanRun=true;document.getElementById("throttle").onscroll=function(){if(!canRun){//判断是否空闲,如果正在运行,直接returnreturn;}canRun=false;setTimeout(function(){console.log("函数节流");canRun=true;},300);};Dom操作前端开发人员都知道Do操作是非常耗时的(我个人测试过30*30的表遍历添加样式)。所以尽量避免频繁的Dom操作,如果不能避免,尽量优化DOm操作。1.:缓存Dom查询,比如通过getElementByTagName('div')获取Dom集合,而不是一个一个获取。2:合并Dom操作,使用createDocumentFragment()varfrag=document.createDocumentFragment()for(i<10){varli=document.createElement('li')frag.appendChild(li)}document.body.appendChild(frag)3:利用React、Vue等框架的虚拟dom(原理还没搞懂),可以更快的实现dom操作。尽量避免重绘(rePaint)和回流(reFlow)。如果用js修改元素的颜色或者背景色,就会触发重绘。重绘的代价还是比较大的,因为浏览器会改变某个DOM元素的视觉效果然后去查看这个DOM元素中的所有节点。如果修改元素的大小和位置,就会发生回流,回流成本更大。它会在某个DOM元素的位置发生变化后触发,它会重新计算所有元素在页面上的位置和占用的区域,这样的话,会导致页面的一部分甚至整个页面被重新渲染。css3硬件加速浏览器渲染时,会分为两层:普通层和复合层。普通的文档流可以理解为复合层。absolute和fixed布局虽然可以脱离普通文档流,但仍然属于普通层,不会开启硬件加速。上面说的重绘(rePaint)和回流(reFlow)是指在普通图层上重绘回流。复合层启用硬件加速。它与普通层不在同一层,因此复合层不会影响普通层。如果将一个元素提升到复合层,再次操作该元素时,不会引起普通层的重绘和回流。这提高了渲染性能。如何开启硬件加速:1.使用translate3d和translateZwebkit-transform:translateZ(0);-moz-transform:translateZ(0);-ms-transform:translateZ(0);-o-transform:translateZ(0);变换:translateZ(0);webkit-transform:translate3d(0,0,0);-moz-transform:translate3d(0,0,0);-ms-transform:translate3d(0,0,0);-o-转换:translate3d(0,0,0);转换:translate3d(0,0,0);2。opacity的使用要求在动画执行过程中会创建复合层,动画还没有开始或结束后元素会回到上一个Status3.使用will-chang属性。此属性不常用。它通常与opacity和translate一起使用。对于webkit浏览器,启用硬件加速有时可能会导致浏览器频繁闪烁或抖动。可以使用以下方法消除:-webkit-backface-visibility:hidden;-webkit-perspective:1000;如果使用硬件加速,请使用z-index配合,因为如果这个元素加了硬件加速,index级别比较低,那么这个元素后面的其他元素(级别都比这个元素高,还是一样的,且releative或absolute属性相同),默认会变成复合层渲染,如果处理不当,避免强制同步布局和布局抖动会极大影响性能。浏览器渲染流程如下:js/css(javascript)>计算样式(style)>布局(layout)>绘图(paint)>渲染复合层(Composite)JavaScript:JavaScript实现动画效果、DOM元素操作等。样式(计算样式):确定应将哪些CSS规则应用于每个DOM元素。布局:计算最终屏幕上显示的每个DOM元素的大小和位置。Paint(绘图):在多个图层上绘制DOM元素的文字、颜色、图像、边框和阴影。Composite(渲染图层合并):将图层按照合理的顺序进行合并,显示在屏幕上。在js中,如果读取style属性的某些值,浏览器会强制进行一次布局,计算,然后返回值,如:offsetTop,offsetLeft,offsetWidth,offsetHeightscrollTop/Left/Width/HeightclientTop/Left/Width/Heightwidth,height请求getComputedStyle(),或者IE的currentStyle所以,如果浏览器在执行JavaScript脚本之前强制执行布局过程,这就是所谓的强制同步布局。例如下面的代码:requestAnimationFrame(logBoxHeight);//先写后读,触发强制布局函数logBoxHeight(){//更新框样式box.classList.add('super-big');//为了返回box的offerHeight值//浏览器必须先应用属性修改,然后执行布局过程console.log(box.offsetHeight);}//先读后写,避免强制布局functionlogBoxHeight(){//获取box.offsetHeightconsole.log(box.offsetHeight);//更新框样式box.classList.add('super-big');}JavaScript脚本运行时,它能拿到的元素样式属性值都是上一帧的,都是旧值。因此,如果在当前框架获取属性之前更改元素节点,将导致浏览器首先应用属性修改,结果执行布局过程,最后执行JavaScript逻辑。如果连续多次强行同步布局,会造成布局抖动。例如,下面的代码:}}作者:SylvanasSun链接:https://juejin.im/post/59da456951882525ed2b706d来源:掘金版权归作者所有。商业转载请联系作者授权,非商业转载请注明出处。我们知道浏览器是逐帧刷新页面的,对于每一帧,上一帧的布局信息是已知的。强制布局就是用js强制浏览器提前布局,比如下面的代码://bed每次循环都需要靠左,会发生回流10console.log(box.style.left)}//googvarwidth=box.offsetWidth;functionresizeAllParagraphsToMatchBlockWidth(){for(vari=0;ib){num=a}else{num=b}//可以用num=a>b代替吗?a:b当判断条件大于3中的情况时,用switch代替if,因为switch的执行速度比if快,尤其是在IE下,速度大约是if的两倍先总结这么多,其实还有很多性能优化,比如预加载,服务端渲染,css选择器优化等等。等有机会再总结