什么是防抖/节流?

简单解释下防抖节流,二者都是在单位时间内,限制 function 被执行的次数。

  • 节流好理解,就是点完一次,停止接待1秒,然后在继续接待,停止过程中你随便点,有反应算我输。
  • 防抖也不复杂,和上面类似,区别是,必须停够1秒才能再点。如果遇到一直不停的点,那就一直不重置,必须老实停1秒不点,才恢复,和我起床一样,越催越起不来。

为什么要使用防抖/节流功能?

防抖节流功能应用范围很广,主要用于防止用户反复点击按钮造成内容多次提交或者事件多次执行,或监听鼠标滚轮及屏幕变化。

防抖函数

/**
 * 防抖核心代码
 * 逻辑是第一次点完以后开始计时,如果单位时间内点了的话不但无效,而且时间从头计算
 *
 * 例如设置3000毫秒,第一次点完如果3秒内再次点击不但不触发任何效果,而且3秒从头开始算
 * 如果一直点一直点,就永远无效
 */
function debounce(fn, timer) {
    let timeout = null;
    return function () {
        if (timeout) {
            clearTimeout(timeout);
        } else {
            fn.apply(this, arguments);
        }
        timeout = setTimeout(() => {
            timeout = null;
        }, timer);
    }
}

节流函数

/**
 * 节流核心代码
 * 逻辑是第一次点完以后开始计时,如果下次点击时间没达到设定时间则无效,否则有效
 *
 * 例如设置3000毫秒,第一次点击完过了1秒点击,判定为无效,立刻记录当前时间
 * 过了2秒点击,与上一次时间对比,不足3秒,判定无效
 * 过了3秒以上点击,与上次时间对比,足够3秒,判定有效,并立刻记录当前时间
 *
 */
function throttle(fn, delay) {
    let begin = 0;
    return function () {
        const current = new Date().getTime();
        if (current - begin > delay) {
            fn.apply(this, arguments);
            begin = current;
        }
    }
}

使用方法

<!-- 这段代码中节流是无法触发的 -->
<button onclick="throttle(click0, 1000)">按钮</button>
<!-- 而这段代码中就可以触发 -->
btn.addEventListener('click', throttle(click0, 1000), false);
<!--
根据我的测试,不推荐放到onclick中触发,如果一定要这样写,就2个方法解决
要么,改写throttle方法,去除return function等,返回值搬到方法里,begin放到函数外面
要么,如下代码申明一个变量,放到onclick中
-->
<button onclick="click">按钮</button>
const click = throttle(() => {
    sp0.innerText = ++c0
}, 1000);