Skip to content

函数防抖

  • 定义:触发事件后,在n秒内函数只能执行一次,如果触发事件后在n秒内又触发了事件,则会重新计算函数延长执行的时间。
  • 个人总结:使重复执行的函数在短时间内只执行最后一次。
  • 实现:
    • 准备一个定时器,把要做的事情放在定时器里;
    • 判断是否存在定时器,没有就开始计时,有就重新计时;
    • 一直重新计时,直到没有操作的时候就只有一个定时器,所以只执行一次;
  • 举个栗子
    • 没有使用防抖的时候
    html
    
    <!-- 给div高度撑出滚动条 -->
    <div style="height: 8000px;width: 100px;"></div>
    <script>
        const showLocaltion = () => {
            //  获取滚动条位置(兼容写法)
            var scrollTop = document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop
            // 没有防抖的时候按方向键也会执行7、8次
            console.log('滚动条位置:', scrollTop)
        }
        // 事件监听
        window.addEventListener('scroll',showLocaltion)
    </script>
    • 使用防抖
    html
    <!-- 滚动条不停滚动,只打印一次滚动条位置-->
    <div style="height: 8000px;width: 100px;"></div>
    <script>
        const showLocaltion = () => {
            //  获取滚动条位置(兼容写法)
            var scrollTop = document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop
            // 按方向键也会执行7、8次
            console.log('滚动条位置:', scrollTop)
        }
        // 事件监听
        // 存储定时器ID
        let timer = null
        window.addEventListener('scroll', () => {
            if (timer) {
                // 有定时器就先清除再重新开始计时
                clearTimeout(timer)
                timer = setTimeout(showLocaltion, 1000)
            } else {
                // 没有定时器就直接开始计时
                timer = setTimeout(showLocaltion, 1000)
            }
        })
    </script>
    • 因为得有个外层变量存储定时器ID,所以也可以使用闭包写法
    html
    <div style="height: 8000px;width: 200px;"></div>
    <script>
        const showLocaltion = () => {
            //  获取滚动条位置(兼容写法)
            var scrollTop = document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop
            // 按方向键也会执行7、8次
            console.log('滚动条位置:', scrollTop)
        }
       
    
        function debounce(fn, delay) {
            let timer = null
            return function () {
                if (timer) {
                    clearTimeout(timer)
                    timer = setTimeout(fn, delay)
                } else {
                    timer = setTimeout(fn, delay)
                }
            }
        }
    
        window.onscroll = debounce(showLocaltion, 1000)
    </script>

函数节流

  • 定义:如果短时间内大量触发同一事件,那么在事件处理函数执行一次之后,该函数在指定的时间期限内不再工作,直至过了这段时间才重新生效。

  • 个人总结:使重复执行的函数每隔一段时间执行一次。

  • 实现:

    • 准备一个开关,事件处理程序根据开关来决定是否执行
    • 开始执行函数之前关闭开关
    • 每隔一段时间之后就打开开关
  • 举个栗子

    html
    <!-- 函数节流 -->
    <!-- 滚动条不停滚动,每隔一秒打印一次位置 -->
    <!-- 准备一个开关,事件处理程序根据开关来决定是否执行 -->
    <!-- 撑出滚动条 -->
    <div style="height: 8000px;width: 100px;"></div>
    <script>
        const showLocaltion = () => {
            var scrollTop = document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop
            console.log('滚动条位置:', scrollTop)
            // 隔段事件后打开开关,下次才能进入该分支
            isGo = true
        }
        // 事件监听
        // 开关
        var isGo = true
        window.addEventListener('scroll', () => {
            if (isGo) {
                // 关掉开关
                isGo = false
                setTimeout(showLocaltion, 1000)
            } else {
                return
            }
        })
    
    
    </script>
    • 闭包写法
    html
    <div style="height: 8000px;width: 200px;"></div>
    <script>
        const showLocaltion = () => {
            var scrollTop = document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop
            console.log('滚动条位置:', scrollTop)
            // 隔段事件后打开开关,下次才能进入该分支
            isGo = true
        }
       
    
        function throttle(fn, delay) {
            let isGo = true
            return function () {
                if (isGo) {
                    // 关掉开关
                    isGo = false
                    setTimeout(()=>{
                        fn()
                        // 隔段事件后打开开关,下次才能进入该分支
                        isGo = true
                    }, delay)
                }else{
                    return
                } 
            }
        }
    
        window.onscroll = throttle(showLocaltion, 1000)
    </script>

应用场景

节流(throttle)

  • DOM元素的拖拽功能实现(mousemove)
  • 搜索联想(keyup)
  • 计算鼠标移动的距离(mousemove)
  • Canvas 模拟画板功能(mousemove)
  • 射击游戏的 mousedown/keydown 事件(单位时间只能发射一颗子弹)
  • 监听滚动事件判断是否到页面底部自动加载更多:给 scroll 加了 debounce 后,只有用户停止滚动后,才会判断是否到了页面底部;如果是 throttle 的话,只要页面滚动就会间隔一段时间判断一次

防抖(debounce)

  • scroll事件滚动触发事件
  • 搜索框输入查询,如果用户一直在输入中,没有必要不停地调用去请求服务端接口,等用户停止输入的时候,再调用,设置一个合适的时间间隔,有效减轻服务端压力。
  • 表单验证
  • 按钮提交事件。
  • 浏览器窗口缩放,resize事件(如窗口停止改变大小之后重新计算布局)等。