学完了防抖,不顺便学学节流吗?

这是我参与8月更文挑战的第23天,活动详情查看:8月更文挑战

前文完整介绍了节流的兄弟:防抖(初始防抖从underscore库中学习debounce,假设掘友暂时不了解这个,相信从这两篇中掘友定会有所收获),本文开始讲解节流

节流的应用场景:当重复调用函数的时候,至少每隔 wait毫秒调用一次该函数。对于想控制一些触发频率较高的事件有帮助。

节流常见应用场景代表有以下几种:

  • dom元素拖拽
  • 计算鼠标移动的距离
  • 监听scroll滚动

先介绍一下本节实例背景:有一个div,在div上移动触发回调函数listenMoveOn,这里使用了简单版本的节流,如下代码所示

第一时间触发,末尾不触发

通过时间戳实现节流,这种方式会在进入throttle函数中就会立即触发事件监听回调,因为old初始值为0now - 0 必定大于wait,所以这种实现方式 首次肯定会触发,详情请看代码

<style>
    div {
        background-color: #666;
        height: 300px;
    }
</style><div></div><script>
    let dom = document.getElementsByTagName("div")[0];
    dom.onmousemove = throttle(listenMoveOn, 200);
    
    function listenMoveOn() {
        // 监听的回调做一些事情 
    }
    /**
     *
     * @param {function} fn - 回调函数
     * @param {number} wait - 触发间隔时间
     */
    function throttle(fn, wait) {
        let timer, old, now, context, args;
        old = 0
​
        return function() {
            now = +new Date()
            context = this
            args = arguments
            if (now - old > wait) { // 因为 now - 0 必定大于wait,所以这种实现方式 首次肯定会触发
                fn.apply(context, args)
                old = now
            }
        }
    }
</script>
复制代码

第一次不立即触发,末尾触发

使用setTimeout实现节流,要等到时间达标才会去触发,所以首次不会触发,后面出去之后由于有setTimeout的存在,所以还会补上一次.

<script>
    /**
     *
     * @param {function} fn - 回调函数
     * @param {number} wait - 触发间隔时间
     */
    function throttle(fn, wait) {
        let timer, context, args;
​
        return function() {
            context = this
            args = arguments
            if (!timer) {
                timer = setTimeout(() => {
                    timer = null    // 确保下次进来时能够重新设置定时器
                    fn.apply(context, args)
                }, wait)
            }
        }
    }
</script>
复制代码

小结

本文简单介绍了两种实现节流的方式,这两种方式都各有特色和应用场景,下一节将参考underscore中的throttle进行解析高配版本的节流,综合这两种的优点,达到可以自由控制第一次和末尾是否触发。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享