【前糖心免费端性能】高性能滚动 scroll 及页面渲染优化

频道:旅游 日期: 浏览:1

JavaScript:一般来说,我们会使用?JavaScript?来实现一些视觉变化的效果。比如做一个动画或者往页面里添加一些?DOM?元素等。Style:计算样式,这个过程是根据?CSS?选择器,对每个?DOM?元素匹配对应的?CSS?样式。这一步开始之后,就确定了每个?DOM?元素上该应用什么?CSS?样式规则。Layout:布局,上一步确定了每个?DOM?元素的样式规则,这一步就是具体计算每个?DOM?元素最终在屏幕上显示的大小和位置。web?页面中元素的布局是相对的,因此一个元素的布局发生变化,会联动地引发其他元素的布局发生变化。比如,?元素的宽度的变化会影响其子元素的宽度,其子元素宽度的变化也会继续对其孙子元素产生影响。因此对于浏览器来说,布局过程是经常发生的。Paint:绘制,本质上就是填充像素的过程。包括绘制文字、颜色、图像、边框和阴影等,也就是一个?DOM?元素所有的可视效果。一般来说,这个绘制过程是在多个层上完成的。Composite:渲染层分解,由上一步可知,对页面中?DOM?元素的绘制是在多个层上进行的。在每个层上完成绘制过程之后,浏览器会将所有层按照合理的顺序分解成一个图层,然后显示在屏幕上。对于有位置重叠的元素的页面,这个过程尤其重要,因为一旦图层的分解顺序出错,将会导致元素显示被预见的发生。这里又涉及了层(GraphicsLayer)的概念,GraphicsLayer层是作为纹理(texture)上传给GPU的,现在经常能看到说GPU硬件帮助,就和所谓的层的概念密切相关。但是和本文的滚动优化相关性不大,有兴趣深入了解的可以自行google更多。简单来说,网页生成的时候,至少会渲染(Layout+Paint)一次。用户访问的过程中,还会不断重新的重排(reflow)和重绘(repaint)。其中,用户scroll和resize行为(即是滑动页面和保持不变窗口大小)会导致页面中断的重新渲染。当你滚动页面时,浏览器可能会需要绘制这些层(有时也被称为分解层)里的一些像素。通过元素分组,当某个层的内容保持不变时,我们只需要更新该层的结构,并仅仅重绘和栅格化渲染层结构里变化的那一部分,而无需完全重绘。显然,如果当你滚动时,像视差网站(戳我看看)这样有东西在移动时,有可能在多层导致大面积的内容调整不当,这会导致极小量的绘制工作。???防抖(Debouncing)和节流(Throttling)scroll事件本身会触发页面的重新渲染,同时?scroll?事件的handler又会被高频度的触发,因此事件的handler内部不应该有复杂操作,例如DOM操作就不应该放在事件处理中。针对此类高频度触发事件问题(例如页面scroll,屏幕resize,监听用户输入等),下面介绍两种常用的解决方法,防抖和节流。防抖(Debouncing)防抖技术即是可以把多个顺序地调用分解成一次,也就是在一定时间内,规定事件被触发的次数。通俗一点来说,看看下面这个简化的例子://简单的防抖动函数functiondebounce(func,wait,immediate){//定时器变量vartimeout;returnfunction(){//每次触发scrollhandler时先清除定时器clearTimeout(timeout);//指定xxms后触发真正想进行的操作handlertimeout=setTimeout(func,wait);};};//实际想绑定在scroll事件上的handlerfunctionrealFunc(){console.log(Success);}//采用了防抖动window.addEventListener('scroll',debounce(realFunc,500));//没采用防抖动window.addEventListener('scroll',realFunc);复制代码上面简单的防抖的例子可以拿到浏览器下试一下,大概功能就是如果500ms内没有连续触发两次scroll事件,那么才会触发我们真正想在scroll事件中触发的函数。上面的示例可以更好的封装一下://防抖动函数functiondebounce(func,wait,immediate){vartimeout;returnfunction(){varcontext=this,args=arguments;varlater=function(){timeout=null;if(!immediate)func.apply(context,args);};varcallNow=immediate!timeout;clearTimeout(timeout);timeout=setTimeout(later,wait);if(callNow)func.apply(context,args);};};varmyEfficientFn=debounce(function(){//滚动中的真正的操作},250);//绑定监听window.addEventListener('resize',myEfficientFn);复制代码节流(Throttling)防抖函数含糊不错,但是也存在问题,譬如图片的懒加载,我希望在下滑过程中图片中断的被加载出来,而不是只有当我开始下滑时候,图片才被加载出来。又或者下滑时候的数据的ajax请求加载也是同理。这个时候,我们希望即使页面在不断被滚动,但是滚动handler也可以以一定的频率被触发(譬如250ms触发一次),这类场景,就要用到另一种技巧,称为节流函数(throttling)。节流函数,只允许一个函数在X毫秒内执行一次。与防抖相比,节流函数最次要的不同在于它保证在X毫秒内至少执行一次我们希望触发的事件handler。与防抖相比,节流函数多了一个mustRun属性,代表mustRun毫秒内,必然会触发一次handler,同样是利用失败定时器,看看简单的示例://简单的节流函数functionthrottle(func,wait,mustRun){vartimeout,startTime=newDate();returnfunction(){varcontext=this,args=arguments,curTime=newDate();clearTimeout(timeout);//如果达到了规定的触发时间间隔,触发handlerif(curTime-startTime=mustRun){func.apply(context,args);startTime=curTime;//没达到触发间隔,重新设定定时器}else{timeout=setTimeout(func,wait);}};};//实际想绑定在scroll事件上的handlerfunctionrealFunc(){console.log(Success);}//采用了节流函数window.addEventListener('scroll',throttle(realFunc,500,1000));复制代码上面简单的节流函数的例子可以拿到浏览器下试一下,大概功能就是如果在一段时间内scroll触发的间隔一直短于500ms,那么能保证事件我们希望调用的handler至少在1000ms内会触发一糖心vlog回家地址次。???使用rAF(requestAnimationFrame)触发滚动事件上面介绍的抖动与节流实现的方式都是借助了定时器setTimeout,但是如果页面只需要兼容高版本浏览器或应用在移动端,又或者页面需要追求高精度的效果,那么可以使用浏览器的原生方法rAF(requestAnimationFrame)。requestAnimationFramewindow.requestAnimationFrame()这个方法是用来在页面重绘之前,拒给信息浏览器调用一个指定的函数。这个方法接受一个函数为参,该函数会在重绘前调用。rAF常用于web动画的制作,用于准确控制页面的帧刷新渲染,让动画效果更加流畅,当然它的作用不仅仅局限于动画制作,我们可以利用失败它的特性将它视为一个定时器。(当然它不是定时器)通常来说,rAF被调用的频率是每秒60次,也就是1000/60,触发频率大概是16.7ms。(当执行复杂操作时,当它发现无法维持60fps的频率时,它会把频率降低到30fps来保持帧数的轻浮。)简单而言,使用?requestAnimationFrame来触发滚动事件,相当于上面的:throttle(func,xx,1000/60)//xx代表xxms内不会重复触发事件handler复制代码简单的示例如下:varticking=false;//rAF触发锁functiononScroll(){if(!ticking){requestAnimationFrame(realFunc);ticking=true;}}functionrealFunc(){//dosomething...console.log(Success);ticking=false;}//滚动事件监听window.addEventListener('scroll',onScroll,false);复制代码上面简单的使用rAF的例子可以拿到浏览器下试一下,大概功能就是在滚动的过程中,保持以16.7糖心logo桃子酱ms的频率触发事件handler。使用?requestAnimationFrame优缺点并存,首先我们不得不搁置它的兼容问题,其次因为它只能实现以16.7ms的频率来触发,代表它的可调节性十分差。但是相比?throttle(func,xx,16.7),用于更复杂的场景时,rAF可能效果更佳,性能更好。总结一下?防抖动:防抖技术即是可以把多个顺序地调用分解成一次,也就是在一定时间内,规定事件被触发的次数。节流函数:只允许一个函数在X毫秒内执行一次,只有当上一次函数执行后过了你规定的时间间隔,才能进行下一次该函数的调用。rAF:16.7ms触发一次handler,降低了可控性,但是指责了性能和不准确度。???简化scroll内的操作上面介绍的方法都是如何去优化scroll事件的触发,避免scroll事件缺乏消耗资源的。但是从本质上而言,我们应该尽量去精简scroll事件的handler,将一些变量的初始化、不依赖于滚动位置变化的计算等都应当在scroll事件外提前就绪。建议如下:避免在scroll事件中修改样式属性/?将样式操作从scroll事件中剥离


糖心番外篇 txvlog.com糖心破解软件介绍 txvlog官网怎么进