防抖与节流

防抖与节流

什么情况下需要防抖与节流:

在一些高频率事件触发的场景下,不希望对应的事件处理函数多次执行

比如:

​ 滚动事件

​ input输入框的模糊查询

轮播图切换

​ 点击操作等

浏览器默认情况下都会有自己的监听事件间隔(谷歌浏览器 4 - 6 ms), 如果检测到多次,就会造成不必要的资源浪费

防抖:对于高频操作来说,我们只希望识别一次点击,即只触发一次对应的事件,第一次或最后一次都可以

节流:对于高频操作,可以自行设定事件触发频率,以使多次触发的事件,在规定时间内,只触发一次

防抖实现:
<button id="btn">点击按钮</button>

    <script>
        let btn = document.getElementById("btn")

        /**
         *  handle 最终要执行的事件监听
         *  wait 事件触发多久后开始执行
         *  immediate 控制执行第一次还是最后一次, false执行最后一次,true执行第一次
        */
       function debounce(handler, wait, immediate){
           //首先对传入的参数进行校验
           if(typeof handler !== 'function'){ throw new Error('handler must be a function')}
           if(typeof wait === 'undefined') wait = 300
           if(typeof wait === 'boolean') {
               immediate = wait
               wait = 300
           }
           let timer = null
           return function proxy(){
               if(timer){
                   clearTimeout(timer)
                 		timer = null
               }
                timer = setTimeout(() => {
                    handler()
                }, wait)
           }
       }
       function btnClick(a,b){
          console.log('点击了123333')
       }
       btn.onclick = debounce(btnClick,false)
    </script>

给wait设定默认值300ms, 在不传wait的情况下默认 300ms内只会触发一次,传值的话就会在指定时间内只触发一次

如果btnClick会有参数传入,如何处理?this如何处理?

改造一下代码

<button id="btn">点击按钮</button>

    <script>
        let btn = document.getElementById("btn")

        /**
         *  handle 最终要执行的事件监听
         *  wait 事件触发多久后开始执行
         *  immediate 控制执行第一次还是最后一次, false执行最后一次,true执行第一次
        */
       function debounce(handler, wait, immediate){
           //首先对传入的参数进行校验
           if(typeof handler !== 'function'){ throw new Error('handler must be a function')}
           if(typeof wait === 'undefined') wait = 300
           if(typeof wait === 'boolean') {
               immediate = wait
               wait = 300
           }
           let timer = null
           return function proxy(...args){
             	//定义变量self接收this
               let self = this
               if(timer){
                   clearTimeout(timer)
                 	timer = null
               }
                timer = setTimeout(() => {
                    handler.call(self,...args)
                }, wait)
           }
       }
       function btnClick(a,b){
         //返回一个匿名函数
           return function fn(){
               console.log('点击了了了了',this, a, b)
           }
       }
       btn.onclick = debounce(btnClick(1,2),false)
    </script>

在我们的debounce函数中,immediate用来控制,是否只执行第一次,如何是immediate参数生效?

改造一下代码:

<button id="btn">点击按钮</button>

    <script>
        let btn = document.getElementById("btn")

        /**
         *  handle 最终要执行的事件监听
         *  wait 事件触发多久后开始执行
         *  immediate 控制执行第一次还是最后一次, false执行最后一次,true执行第一次
        */
       function debounce(handler, wait, immediate){
           //首先对传入的参数进行校验
           if(typeof handler !== 'function'){ throw new Error('handler must be a function')}
           if(typeof wait === 'undefined') wait = 300
           if(typeof wait === 'boolean') {
               immediate = wait
               wait = 300
           }
           if(typeof immediate !== 'boolean') immediate = false
           let timer = null
           return function proxy(...args){
               let self = this,
                init = immediate && !timer     //定义一个变量,控制是否只执行第一次
               if(timer){
                   clearTimeout(timer)
                 	 timer = null
               }
                timer = setTimeout(() => {
                    timer = null
                    //如果immediate为true则不会触发handler
                    !immediate ? handler.call(self,...args) : null
                }, wait)
                //timer为null 且 传入的immediate为true
                init ? handler.call(self, ...args) : null
           }
       }
       function btnClick(a,b){
           return function fn(){
               console.log('点击了了了了',this)
           }
       }
       btn.onclick = debounce(btnClick(),300, true)
    </script>
节流实现:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        body{
            height: 5500px;
        }
    </style>
</head>
<body>
    
    <script>

        function throttle(handler, wait){
            if(typeof handler !== 'function') throw new Error("handler must be a function")
            if(typeof wait === 'undefined') wait = 400     //给wait默认值400ms

            let previous = 0      //定义变量记录上一次执行的时间
            let timer = null      //管理定时器
            return function proxy(...args){
                let now = new Date()
                let self = this
                let interval = wait - (now - previous)
                
                //interval<= 0 说明是非高频次操作,可以执行handle
                if(interval <= 0){
                    clearTimeout(timer)
                    timer = null
                    handler.call(self, ...args)
                    previous = new Date()
                }else if(!timer){   
                    // 另一种情况是此时interval > 0  我们就讲下次执行结果存在定时器中, 且不可能一直去存储,只有 timer = null时采取存储
                    timer = setTimeout(() => {
                        //清掉上一个定时器
                        clearTimeout(timer)  //这个操作只是吧系统中定时器清除掉了,但是timer中的值还在,因此需要在下面将timer置位null
                        timer = null
                        //执行操作
                        handler.call(self, ...args)
                        previous = new Date()
                    },interval)
                }
            }
        }

        function scroll(){
            console.log("滚动了")
        }
        window.onscroll = throttle(scroll, 600)
    </script>
</body>
</html>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值