0


JS—节流与防抖

一、js防抖和节流

在进行窗口的resize、scroll、输出框内容校验等操纵的时候,如果事件处理函数调用的频率无限制,会加重浏览器的负担,导致用户体验非常之差。那么为了前端性能的优化也为了用户更好的体验,就可以采用防抖(debounce)和节流(throttle)的方式来到达这种效果,减少调用的频率。

二、为什么滚动scroll、窗口resize等事件需要优化

滚动事件的应用很频繁:图片懒加载、下滑自动加载数据、侧边浮动导航栏等。

在绑定scroll、resize事件时,但它发生的时候,它被触发的频率非常高,间隔很近。在日常开发的页面中,事件中涉及到的大量的位置计算、DOM操作、元素重绘等等这些都无法在下一个scroll事件出发前完成的情况下,浏览器会卡帧。

三、滚动和页面渲染前端性能优化的关系

为什么滚动需要优化?前面提到了事件中涉及到大量的位置计算、DOM操作、元素重绘等等,这些又与页面的渲染有关系,页面渲染又与前端的性能优化有关系?套娃一样,一层套着一层,每一层都联系紧密,每一层都如此平凡且重要。

review一下前端的渲染和优化

web页面展示经历的步骤:js—style—layout—paint—composite,简单回顾一下,在这里不做详细的介绍哦!

网页生成的时候,至少会渲染(Layout+Paint)一次。用户访问的过程中,还会不断重新的重排(reflow)和重绘(repaint),用户scroll行为和resize行为会导致页面不断的进行重新渲染,而且间隔频繁,容易造成浏览器卡帧。

四、防抖Debounce

(1)防抖Debounce情景

①有些场景事件触发的频率过高(mousemove onkeydown onkeyup onscroll)

②回调函数执行的频率过高也会有卡顿现象。 可以一段时间过后进行触发去除无用操作

(2)防抖原理

一定在事件触发 n 秒后才执行,如果在一个事件触发的 n 秒内又触发了这个事件,以新的事件的时间为准,n 秒后才执行,等触发事件 n 秒内不再触发事件才执行。

官方解释:当持续触发事件时,一定时间段内没有再触发事件,事件处理函数才会执行一次,如果设定的时间到来之前,又一次触发了事件,就重新开始延时。

(3)防抖函数简单实现

//简单的防抖函数functiondebounce(func, wait, immediate){//定时器变量var timeout;returnfunction(){//每次触发scrolle,先清除定时器clearTimeout(timeout);//指定多少秒后触发事件操作handler
            timeout =setTimeout(func, wait);};};//绑定在scrolle事件上的handlerfunctionhandlerFunc(){
        console.log('Success');}//没采用防抖动
    window.addEventListener('scroll', handlerFunc);//采用防抖动
    window.addEventListener('scrolle',debounce(handlerFunc,1000));

(4)防抖函数的演化过程

①this event绑定问题
//以闭包的形式返回一个函数,内部解决了this指向的问题,event对象传递的问题functiondebounce(func, wait){var timeout;returnfunction(){var context =this;var args = arguments;clearTimeout(timeout)
            timeout =setTimeout(function(){func.apply(context, args)}, wait);};};
②立即触发问题
//首次触发执行,再次触发以后开始执行防抖函数//使用的时候不用重复执行这个函数,本身返回的函数才具有防抖功能functiondebounce(func, wait, immediate){var timeout;returnfunction(){var context =this;var args = arguments;if(timeout)clearTimeout(timeout);// 是否在某一批事件中首次执行if(immediate){var callNow =!timeout;
            timeout =setTimeout(function(){
                timeout =null;func.apply(context, args)
                immediate =true;}, wait);if(callNow){func.apply(context, args)}
            immediate =false;}else{
            timeout =setTimeout(function(){func.apply(context, args);
                immediate =true;}, wait);}}}
③返回值问题
functiondebounce(func, wait, immediate){var timeout, result;returnfunction(){var context =this, args = arguments;if(timeout)clearTimeout(timeout);if(immediate){var callNow =!timeout;
            timeout =setTimeout(function(){
                result =func.apply(context, args)}, wait);if(callNow) result =func.apply(context, args);}else{
            timeout =setTimeout(function(){
                result =func.apply(context, args)}, wait);}return result;}}
④取消防抖,添加cancel方法
functiondebounce(func, wait, immediate){var timeout, result;functiondebounced(){var context =this, args = arguments;if(timeout)clearTimeout(timeout);if(immediate){var callNow =!timeout;
            timeout =setTimeout(function(){
                result =func.apply(context, args)}, wait);if(callNow) result =func.apply(context, args);}else{
            timeout =setTimeout(function(){
                result =func.apply(context, args)}, wait);}return result;}
    debounced.cancel=function(){cleatTimeout(timeout);
        timeout =null;}return debounced;}

五、节流Throttle

(1)节流Throttle情景

①图片懒加载

②ajax数据请求加载

(2)节流原理

如果持续触发事件,每隔一段时间只执行一次函数。

官方解释:当持续触发事件时,保证一定时间段内只调用一次事件处理函数。

(3)节流实现—时间戳和定时器

  • 时间戳
varthrottle=function(func, delay){var prev = Date.now()returnfunction(){var context =this;var args = arguments;var now = Date.now();if(now - prev >= delay){func.apply(context, args);
                prev = Date.now();}}}functionhandle(){
        console.log(Math.random());}
    window.addEventListener('scroll',throttle(handle,1000));
  • 定时器
varthrottle=function(func, delay){var timer =null;returnfunction(){var context =this;var args = arguments;if(!timer){
                timer =setTimeout(function(){func.apply(context, args);
                    timer =null;}, delay);}}}functionhandle(){
        console.log(Math.random());}
    window.addEventListener('scroll',throttle(handle,1000))

(4)节流函数的演化过程

①时间戳触发
//在开始触发时,会立即执行一次; 如果最后一次没有超过 wait 值,则不触发functionthrottle(func, wait){var context, args;var previous =0;// 初始的时间点,也是关键的时间点returnfunction(){var now =+newDate();
        context =this;
        args = arguments;if(now - previous > wait){func.apply(context, args);
            previous = now;}}}
②定时器触发
//首次不会立即执行,最后一次会执行,和用时间戳的写法互补。functionthrottle(func, wait){var context, args, timeout;returnfunction(){
        context =this;
        args = arguments;if(!timeout){
            timeout =setTimeout(function(){func.apply(context, args);
                timeout =null;}, wait);}}}
③结合时间戳和定时器
functionthrottle(func, wait){var timer =null;var startTime = Date.now();returnfunction(){var curTime = Date.now();var remaining = wait-(curTime-startTime);var context =this;var args = arguments;clearTimeout(timer);if(remaining<=0){func.apply(context, args);

            startTime = Date.now();}else{
            timer =setTimeout(fun, remaining);// 如果小于wait 保证在差值时间后执行}}}

六、节流防抖总结

防抖:原理是维护一个定时器,将很多个相同的操作合并成一个。规定在delay后触发函数,如果在此之前触发函数,则取消之前的计时重新计时,只有最后一次操作能被触发。

节流:原理是判断是否达到一定的时间来触发事件。某个时间段内只能触发一次函数。

区别:防抖只会在最后一次事件后执行触发函数,节流不管事件多么的频繁,都会保证在规定时间段内触发事件函数。

标签: 前端 javascript ES6

本文转载自: https://blog.csdn.net/weixin_45709829/article/details/123910592
版权归原作者 傲娇味的草莓 所有, 如有侵权,请联系我们删除。

“JS—节流与防抖”的评论:

还没有评论