闭包进阶应用(4)- 防抖和节流

闭包进阶应用(4)- 防抖和节流

函数的防抖 => 对于频繁触发某个操作,只识别一次

<body>
    <button id='btn'>点我</button>

    <script>
        const btn = document.querySelector('#btn');
        btn.addEventListener('click', () => {
            console.log('点击');
        })
    </script>
</body>

假设我们有一个按钮,每次点击都会执行一次点击事件。如果用户频繁点击的话,会造成性能的浪费,甚至可能会让浏览器崩掉。防抖可以让规定时间内的重复操作只执行一次

// func => 要执行的函数
// wait => 频繁设定的界限
//immediate => true为第一次 false为最后一次
const btn = document.querySelector('#btn');
btn.addEventListener('click', debounce(handleClick));
function handleClick(){
    console.log(this);
}
function debounce(func, wait = 300, immediate = false){
    let timer = null;
    return function (...params) {
        clearTimeout(timer);// 每次点击时,都把之前的定时器清空
        timer = setTimeout(() => {
            timer = null; //回归初始状态 保证下一轮点击 timer = null
            func.call(this, ...params);//把点击事件的 this 和传入的 arguments 给到函数
        }, wait);
    }
}

这样,每次点击时,debounce 函数返回一个函数给点击事件事件调用。每次点击都清空之前的定时器,创造一个新的定时器,这样 wait 时间段内,多次点击只会刷新计时器,等点击结束,计时器时间结束,函数执行。

接下来,我们考虑 immediate 参数的问题。

//immediate 为 true 时,执行第一次触发的函数。false 则触发最后一次。
function debounce(func, wait = 300, immediate = false){
    let timer = null;
    return function (...params) {
        // 判断是否为第一次点击
        let nowFlag = immediate && !timer;
        clearTimeout(timer);
        timer = setTimeout(() => {
            timer = null; //回归初始状态
            // 若 immediate 为 false 不执行定时器里的函数
            !immediate ? func.call(this, ...params) : null;
        }, wait);
        // 若第一次点击 nowFlag 为 true,直接执行 func
        nowFlag ? func.call(this, ...params) : null;  
    }
}
// 一个简单的防抖函数就完成了

函数的节流 => 在一段频繁操作中,可以触发多次函数,但触发的频率由自己决定

<body>
<div style="width: 100vw; height: 300vh; background-color:aqua"></div>

<script>
    window.addEventListener('scroll', () => {
        console.log('OK');
    })
</script>
</body>

假设我们需要对一个可以滚动的页面添加滚动事件。每一次滚动,浏览器有最快反应时间(5ms-7ms),触发频率太高。节流函数可以被用来控制此频率

<body>
    <div style="width: 100vw; height: 300vh; background-color:aqua"></div>

    <script>
        window.addEventListener('scroll', throttle(handle));
        function handle(){
            console.log('OK');
        }
        function throttle(func, wait = 300){
            let timer = null,
                previous = 0 //记录上一次的时间
            return function (...params) {
                let now = new Date();
                let remain = wait - (now - previous); //距离触发函数还有多长时间
                if(remain <= 0){
                    // 每一次触发时,我们都要把定时器清空,并把 timer 置为 null,让其为初始状态
                    clearTimeout(timer);
                    timer = null;
                    // 这一次操作的时间作为下一次的 上一次(previous)的时间
                    previous = now;
                    // 执行目标函数
                    func.call(this, ...params);
                }else if(!timer){
                    timer = setTimeout(() => {
                        timer = null;
                        // 下一次的 previous 应为执行此函数时的时间,而不是 now
                        previous = new Date();
                        func.call(this, ...params);
                    }, remain)
                }
            }
        }
    </script>
</body>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值