手写实现函数节流和防抖


前话

  • 为什么要有函数节流和防抖:为了提高性能,去掉一些没有必要的函数调用,把没有必要的给过滤掉
  • 补充:
    • window.onresize — 当拖动屏幕窗口,改变其窗口大小的时候会频繁触发
    • window.mousemove — 当鼠标移动的时候,会非常高频的触发

事件频繁触发可能造成的问题

  1. 事件频繁触发可能造成的问题?
  • (1). 一些浏览器事件:window.onresize、window.mousemove等,触发的频率非常高,会造成浏览器性能问题
  • (2). 如果向后台发送请求,频繁触发,对服务器造成不必要的压力,比如进行搜索框输入搜索的时候

函数节流(throttle)

函数节流的理解与场景

  • 1). 理解:
    • 在函数需要频繁触发时: 函数执行一次后,只有大于设定的执行周期后才会执行第二次
    • 适合多次事件按时间做平均分配触发
  • 2). 场景:
    • 窗口调整(resize)
    • 页面滚动(scroll)
    • DOM 元素的拖拽功能实现(mousemove)
    • 抢购疯狂点击(click)

测试函数节流

  • 下述的代码案例中,可以将时间划分为每2秒为一个时间段,在每一个2秒开始的那一瞬间只会执行一次
<body>
    <button id="throttle">测试函数节流</button>
</body>
<script src="https://cdn.bootcss.com/lodash.js/4.17.15/lodash.js"></script>
<script>
    // 处理点击事件的回调函数
    function handleClick(event) {
        console.log("处理点击事件", this, event)
    }

    // 使用lodash中的 throttle() 
    // 参数一:指定要处理的事件
    // 参数二:延迟的时间
    // 参数三:配置对象
    document.getElementById('throttle').onclick = _.throttle(handleClick, 2000, {
        // 就是让它最后一次不会调用(默认是会调用最后一次)
        // 我们设定2秒为一个时间间隔
        // 下一个2秒开始计时的那一瞬间,就会触发一次
        'trailing': false
    })
</script>

手写函数节流

<body>
    <button id="throttle">测试函数节流</button>
</body>
<script>
    // 用来返回节流函数的工具函数
    function throttle(callback, delay) {
        console.log('1111111111111') // 一上来,不点击按钮就会执行一次,有且仅会执行一次,后续点击按钮都不会执行
        let pre = 0 //pre不要设置成Date.now() , 否则第一次点击的时候是不会调用的
        return function (event) { //这个才是真正的【节流函数】或者说是【真正的事件回调函数】,this是触发事件的节点,即标签。
            console.log('你点击按钮了') // 这个函数会高频触发,因为是点击按钮,无法限制
            // 获取当前的时间
            const current = Date.now()
            if (current - pre > delay) { 
                // 节流:说白了,就是需要满足【上一次调用handleClick函数已经过了delay的时间差了】,然后才去调用 【handleClick函数】
                // 【调用】真正【处理事件的回调函数】 , 并且将真正【处理事件的回调函数,即下面的handleClick函数里的this】中的this
                callback.call(this, event)
                // 记录下,调用handleClick函数用来多长时间
                pre = current
            }
        }
    }
</script>
<script>
    // 处理点击事件的回调函数
    function handleClick(event) {
        console.log("处理点击事件", this, event)
    }

    // 使用自己定义的【工具函数】
    document.getElementById('throttle').onclick = throttle(handleClick, 2000)
</script>

函数防抖(debounce)

函数防抖的理解与场景

  • 1). 理解:
    • 在函数需要频繁触发时: 在规定时间内,只让最后一次生效,前面的不生效。
    • 适合多次事件一次响应的情况。具体地说,就是想要触发一次函数调用,则下一次的触发必须要在我指定的时间之后,如果之前的每两个触发间隔小于我的时间,那么我就认为是客户不小心发生了抖动
  • 2). 场景:
    • 输入框实时搜索联想(keyup/input)

测试函数节流

  • 在下面的代码中,只会在【过了】2s后才会调用一次
<body>
    <button id="debounce">测试防抖函数</button>
</body>
<script src="https://cdn.bootcss.com/lodash.js/4.17.15/lodash.js"></script>
<script>
    function handleClick(event) {
        console.log('处理点击事件', this, event)
    }

    document.getElementById('debounce').onclick = _.debounce(handleClick, 2000)
</script>

手写函数防抖

<body>
    <button id="debounce">测试防抖函数</button>
</body>
<script>
    // 这也是项目优化的一种
    function debounce(callback, delay) {
        return function (event) { //this是事件源
            // 判断对象上是否有某个属性的方式如下:
            // 方式一:
            //  if (callback.timeoutId) {}  会去原型链找
            // 方式二:
            // callback.hasOwnProperty('timeoutId') ---- 效率更高,只会在自身找,不会到原型链上找
            if (callback.hasOwnProperty('timeoutId')) {
                clearTimeout(callback.timeoutId)
            }

            // 虽然我也不知道为什么要把timeoutIdd挂载到callback上面,那就先记住吧
            callback.timeoutId = setTimeout(() => { //必须是箭头函数,否则下面的this就有问题
                callback.call(this, event) //修改callback的this为事件源
                // 删除,标识handleClick已经处理完
                delete callback.timeoutId
            }, delay);
        }
    }

    function handleClick(event) {
        console.log('处理点击事件', this, event)
    }

    document.getElementById('debounce').onclick = debounce(handleClick, 2000)
</script>

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值