最新公告
  • 欢迎您光临网站无忧模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 手撕代码系列(三):一石二鸟探寻防抖和节流的多种实现思路

    正文概述 掘金(鼠子的前端CodeLife)   2021-02-07   538

    前言

    防抖节流是前端性能优化的两大利器,核心思想都是限制高频行为

    它们的区别在于:

    • 防抖,意在当外界不再变化时,再去做响应。

    • 节流,意在不管外界如何变化,始终保持着自己的响应频率。

    应用场景:

    • 防抖:用户疯狂点击提交按钮,用户每次点击提交都会向服务器发出请求,如果不做限制那么会无意义地消耗服务器资源。因此,我们利用防抖的思想,做到当用户停止点击按钮后,再去放出请求。防抖演示图如下:

    手撕代码系列(三):一石二鸟探寻防抖和节流的多种实现思路

    • 节流:当用户在更改浏览器窗体大小时,会触发resize事件。内置的resize事件响应频率太高,不仅对用户体验没有提升,反而还消耗了大量主线程的资源,导致卡顿。因此我们更希望他能降低响应的频率,那么节流的思想就很好的对应了这个需求。节流演示图如下(这里用scroll来做实验):

    手撕代码系列(三):一石二鸟探寻防抖和节流的多种实现思路

    定时器版本

    防抖和节流的定时器都只需要简单的设置和清除一下定时器,首先我们先写防抖。

    防抖代码如下:

    function debounce(fn, delay) {
        let timer = null;
        return function(...args) {
            if(timer) clearTimeout(timer);
            timer = setTimeout(function() {
                fn(...args);
            },delay)
        }
    }
    

    在此基础上,节流仅需改动两行代码:

    function throttle(fn, delay) {
        let timer = null;
        return function(...args) {
            // 第一处改动
            if(timer) return;
            timer = setTimeout(function(){
                // 第二处改动
                timer = null;
                fn(...args);
            },delay)
        }
    }
    

    补充说明:不得不提一嘴,上述代码如果fn内部用到了this,那么this指向哪呢?在非严格模式下是全局对象(浏览器环境为window)。在严格模式下则是undefined。所以,如果fn用到了this,那么它的表现可能会不符合你的预期。为此,我们要么借助bindapplycall去显式绑定this,要么用箭头函数的形式去声明fn,从而让this的指向更符合我们的直觉。

    用 rAF 去做节流

    rAF,即requestAnimationFrame,因篇幅受限本文不再对该函数进行分析。大家可以参考昊神的文章。

    在这里,我们简单地将rAF看成一个间隔是 16.7ms 的定时器(当然它们不完全等价),我们把最小间隔时间固定为了约 16.7ms,据此来实现 N*16.7ms 的效果。相比于一般定时器而言,rAF可是要“守时”的多。

    这里只是出于研究的目的去拓宽思路,大家了解下即可,本人也没有去验证其可靠性

    function throttle(fn,delay) {
        // 估算一下最大计次数
        let maxCount = delay/(1000/60),
            count = 0;
        return function(...args) {
            requestAnimationFrame(function() {
              count++;
              if(count > maxCount) {
                  fn(...args);
                  count = 0;
              }
            });
        }
    }
    

    补充说明:这段代码存在一个问题,它无法保证最后一次回调函数一定被执行。即若持续触发resize3 秒,而节流要求的间隔时间为 2 秒,那么我们预期的效果是在 4 秒左右会响应两次,但上述代码只会响应一次,最后一次将被丢失。 下面的动图演示了这个 BUG。 手撕代码系列(三):一石二鸟探寻防抖和节流的多种实现思路

    用 rIC 去做防抖

    rIC,即requestIdleCallback,大家同样可以参考昊神的文章。

    rIC的空闲回调可能执行的时机有两种,要么是每帧之间的间隔时间,要么是用户停止交互后可以匀出个约 50ms 的时间。我们做防抖可以利用后者。

    从防抖的目标出发,当用户不再频繁做点击交互时,我们再去进行响应。那么如何能够获知用户不再进行操作呢?就是通过判断空闲回调函数的入参IdleDeadline.timeRemaining()的值是否介于 16.7ms 到 50ms 之间,虽然它并不完全可靠。

    注意:这里只是出于研究的目的去拓宽思路,大家了解下即可,本人也没有去验证其可靠性

    function debounce(fn) {
        let lock = false;
        return function(...args) {
            // 上锁防止重复调用
            if (lock) return;
            const run = function() {
                requestIdleCallback(function(deadline) {
                    // 打印一下空闲时间
                    console.log(deadline.timeRemaining());
                    lock = true;
                    // 判断空闲时间
                    if (deadline.timeRemaining() > 1000 / 60) {
                        fn(...args);
                        // 解锁
                        lock = false;
                    } else {
                        // 递归
                        run();
                    }
                });
            }
            run();
        }
    }
    

    下面让我们来演示一下。
    手撕代码系列(三):一石二鸟探寻防抖和节流的多种实现思路 从演示图中可以看出,平均点击2,3次将触发一次响应,离我们真正业务要求还有一定的距离。

    写在最后

    本文给出了常用的实现防抖和节流的方法,并借助rAFrIC做了简单实验。建议大家可以看看lodash是怎么封装和实现的防抖与节流的。对于新手来说,也可以从防抖和节流的实现去体验闭包的妙用!

    关于我

    喜欢聊天、喜欢分享、喜欢前沿的22届小菜鸡,初来乍到希望得到各位大佬的关注。能有实习/校招机会就更好啦!
    个人公众号:鼠子的前端CodeLife


    下载网 » 手撕代码系列(三):一石二鸟探寻防抖和节流的多种实现思路

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元