阅读 75

防抖(debounce)节流(throttle)

一、防抖

1.原理

事件频繁触发的情况下,只有触发的间隔超过指定间隔时,任务才会执行。

(大白话就是,你尽管触发事件,但是我一定在事件触发 n 秒后才执行,如果你在一个事件触发的 n 秒内又触发了这个事件,那我就以新的事件的时间为准,n 秒后才执行)

export const Debounce = (func, wait) => {
    var wait = wait || 200;
    var timeout;

    return function () {
        /*
          1.将this指向正确的对象。
          使用debounce函数时,打印this会指向Window对象,
          所以用context绑定上下文
        */
        var context = this;
        
        /*
          2.arguments:将不确定的变量替换到函数中了。
            Eg:在test()方法中,由于我们不确定变量有多少,比如
            test("古天乐", "太阳才能黑的男人"),
            又或者 test("渣渣辉", [1, 2, 3], 10),
            这时候只需要在函数 test 中用 arguments 接收就行了。
        */
        var args = arguments;
        
        // 3、每次当用户点击/输入的时候,把前一个定时器清除
        clearTimeout(timeout)
        
        // 4、创建一个新的 setTimeout,
              这样能保证点击按钮后的timeout间隔内如果用户还点击了的话,
              就不会执行 fn 函数
        timeout = setTimeout(function(){
            func.apply(context, args)
        }, wait);
    }
}
复制代码
// 防抖的应用。
methods:{
    onClick:Debounce(function(){
        ...
    }, 1000)
}
复制代码

还有一种场景,点击事件后立刻执行,等到停止触发 n 秒后,才可以重新触发执行。

export const 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;
            }, wait)
            if (callNow) func.apply(context, args)
        }
        else {
            timeout = setTimeout(function(){
                func.apply(context, args)
            }, wait);
        }
    }
}
复制代码

立即执行的使用场景:

  • window 的 resize、scroll
  • input的双向绑定,即输完之后等外n毫秒时间后才赋值
  • 鼠标移入移出...

二、节流

  • 1.原理

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

关于节流的实现,有两种实现方式,一种是使用时间戳,一种是设置定时器。

  • 2.时间戳节流
/*
    当触发事件的时候,我们取出当前的时间戳,
    然后减去之前的时间戳(最一开始值设为 0 ),
    如果大于设置的时间周期,就执行函数,然后更新时间戳为当前的时间戳,
    如果小于,就不执行。
*/
export const 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;
        }
    }
}
复制代码
// 节流的应用。
methods:{
    onClick:Debounce(function(){
        ...
    }, 1000)
}
复制代码
  • 3.定时器节流
/*
    当触发事件的时候,我们设置一个定时器,
    再触发事件的时候,如果定时器存在,就不执行,
    直到定时器执行,然后执行函数,
    清空定时器,这样就可以设置下个定时器。
*/
function throttle(func, wait) {
    // 1、通过闭包保存一个标记
    var timeout;

    return function() {
        context = this;
        args = arguments;
        // 2、在函数开头判断定时器是否存在,存在则中断函数
        if (!timeout) {
        
            timeout = setTimeout(function(){
                //3、执行完事件(比如调用完接口)之后,重新将这个标志设置为null
                timeout = null;
                func.apply(context, args)
            }, wait)
            
        }
    }
}
复制代码

节流的应用场景

- 懒加载要监听计算滚动条的位置,使用节流按一定时间的频率获取
- 用户点击提交按钮,假设我们知道接口大致的返回时间的情况下,
  我们使用节流,只允许一定时间内点击一次。
复制代码

防抖和节流减少浏览器不必要损耗的原因

主要涉及到浏览器渲染页面的机制

// 具体信息自己额外补充吧
- 浏览器解析 URL
- 重绘与回流复制代码
关注下面的标签,发现更多相似文章
评论