您现在的位置是:群英 > 开发技术 > web开发
新手对JavaScript对节流,防抖动怎样理解
Admin发表于 2022-05-26 17:20:11869 次浏览
这篇文章给大家分享的是“新手对JavaScript对节流,防抖动怎样理解”,文中的讲解内容简单清晰,对大家学习和理解有一定的参考价值和帮助,有这方面学习需要的朋友,接下来就跟随小编一起学习一下“新手对JavaScript对节流,防抖动怎样理解”吧。


一、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 防抖函数简单实现

    //简单的防抖函数
    function debounce(func, wait, immediate) {
        //定时器变量
        var timeout;
        return function () {
            //每次触发scrolle,先清除定时器
            cleartimeout(timeout);
            //指定多少秒后触发事件操作handler
            timeout = settimeout(func, wait);
        };
    };
    //绑定在scrolle事件上的handler
    function handlerfunc() {
        console.log('success');
    }
    //没采用防抖动
    window.addeventlistener('scroll', handlerfunc);
    //采用防抖动
    window.addeventlistener('scrolle', debounce(handlerfunc, 1000));

4 防抖函数的演化过程

①this event绑定问题

    //以闭包的形式返回一个函数,内部解决了this指向的问题,event对象传递的问题
    function debounce(func, wait) {
        var timeout;
        return function () {
            var context = this;
            var args = arguments;
            cleartimeout(timeout)
            timeout = settimeout(function () {
                func.apply(context, args)
            }, wait);
        };
    };

②立即触发问题

    //首次触发执行,再次触发以后开始执行防抖函数
    //使用的时候不用重复执行这个函数,本身返回的函数才具有防抖功能
function debounce(func, wait, immediate) {
    var timeout;
    return function () {
        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);
        }
    }
}

③返回值问题

function debounce(func, wait, immediate) {
    var timeout, result;
    return function () {
        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方法

function debounce(func, wait, immediate) {
    var timeout, result;
    function debounced () {
        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 节流实现—时间戳和定时器

时间戳

    var throttle = function (func, delay) {
        var prev = date.now()
        return function () {
            var context = this;
            var args = arguments;
            var now = date.now();
            if (now - prev >= delay) {
                func.apply(context, args);
                prev = date.now();
            }
        }
    }

    function handle() {
        console.log(math.random());
    }
    window.addeventlistener('scroll', throttle(handle, 1000));

定时器

    var throttle = function (func, delay) {
        var timer = null;
        return function () {
            var context = this;
            var args = arguments;
            if (!timer) {
                timer = settimeout(function () {
                    func.apply(context, args);
                    timer = null;
                }, delay);
            }
        }
    }

    function handle() {
        console.log(math.random());
    }
    window.addeventlistener('scroll', throttle(handle, 1000))

4 节流函数的演化过程

①时间戳触发

//在开始触发时,会立即执行一次; 如果最后一次没有超过 wait 值,则不触发
function throttle(func, wait) {
    var context, args;
    var previous = 0; // 初始的时间点,也是关键的时间点

    return function() {
        var now = +new date();
        context = this;
        args = arguments;
        if (now - previous > wait) {
            func.apply(context, args);
            previous = now;
        }
    }
}

②定时器触发

//首次不会立即执行,最后一次会执行,和用时间戳的写法互补。
function throttle(func, wait){
    var context, args, timeout;
    return function() {
        context = this;
        args = arguments;
        if(!timeout) {
            timeout = settimeout(function(){
                func.apply(context, args);
                timeout = null;
            }, wait);
        }
    }
}

③结合时间戳和定时器

function throttle(func, wait) {

    var timer = null;
    var starttime = date.now();  

    return function(){
        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对节流,防抖动怎样理解”已经有了进一步的了解,更多相关的问题,欢迎关注群英网络或到群英官网咨询客服。

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:mmqy2019@163.com进行举报,并提供相关证据,查实之后,将立刻删除涉嫌侵权内容。

相关信息推荐
2022-06-16 09:26:23 
摘要:两种修改方法:1、访问指定数组元素并重新赋值,语法“数组名[下标]=新值;”或“数组名["键名"]=新值;”;2、用array_splice()从指定位置开始替换一个指定元素,语法“array_splice(数组,开始位置,1,替换值)”。
2022-05-18 17:32:30 
摘要:call的基本使用var ary = [12, 23, 34];ary.slice();以上两行简单的代码的执行过程为:ary这个实例通过原型链的查找机制找到array.prototype上的slic
2022-11-30 17:55:27 
摘要:php实现满足条件后跳转页面的方法:1、通过“if($ok){header("location:ok.php");}”语法实现;2、通过“if($login){header("location:checkPassword.php");}”方式判断跳转;3、在PHP头部使用“if(...){header("Location: nextPage.php");}”语法实现跳转即可。
云活动
推荐内容
热门关键词
热门信息
群英网络助力开启安全的云计算之旅
立即注册,领取新人大礼包
  • 联系我们
  • 24小时售后:4006784567
  • 24小时TEL :0668-2555666
  • 售前咨询TEL:400-678-4567

  • 官方微信

    官方微信
Copyright  ©  QY  Network  Company  Ltd. All  Rights  Reserved. 2003-2019  群英网络  版权所有   茂名市群英网络有限公司
增值电信经营许可证 : B1.B2-20140078   粤ICP备09006778号
免费拨打  400-678-4567
免费拨打  400-678-4567 免费拨打 400-678-4567 或 0668-2555555
微信公众号
返回顶部
返回顶部 返回顶部