重新认识防抖和节流

123 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第11天,点击查看活动详情

前言

函数的 防抖和节流 是经典的面试题了,面试官为什么喜欢考这个呢,是因为不论在工作还是项目中都可以起到 性能优化 的作用,这也是比较常见而且简单的优化手段了。

防抖

概念: 在事件触发一段时间里只执行最后一次。

这里提到了 只执行最后一次 ,那我们怎么让它只执行最后一次? 实现了这样的效果,就是真正的防抖函数了。

我们来模拟一下输入时发送请求的场景:

<input type="" name="" class="inp">

js 代码:

const inp = document.querySelector('.inp');
function oninput (e) {
    // 发送请求
    console.log(e.target.value);
}
inp.addEventListener('input', oninput) 

上述代码中,只要输入一个字符,就会发送一次请求,会造成大量的资源浪费,虽然服务器顶得住,但难免是不好的,我认为前端的工作就是 用最少的代码,实现最优的效果

那既然输入一个字符就发一次,那么我们能不能延迟 1s 再发呢,这个时候 就需要定时器 setTimeout 了。

const inp = document.querySelector('.inp');
function oninput (e) {
    setTimeout(() => {
        // 发送请求
        console.log(e.target.value);
    }, 1000)
}
inp.addEventListener('input', oninput);

GIF 2022-4-11 22-06-16.gif

看来是不行~~

因为当我们触发 input 事件时,都会新增一个定时器,虽然实现延迟的效果,但没有实现我们说的 只执行最后一次,这样的效果。

那我们稍微优化一下代码。

const inp = document.querySelector('.inp');
let timer;
function oninput (e) {
    clearTimeout(timer);
    timer = setTimeout(() => {
        // 发送请求
        console.log(e.target.value);
    }, 1000)
}
inp.addEventListener('input', oninput);

GIF 2022-4-11 22-18-14.gif

好像是成功啦​ 😄 哈哈哈~~

我们输入6个字符,结果只出现了一次。我们把代码封装一下。

// debounce.jslet inp = document.querySelector('.inp');
​
function oninput (e) {
    console.log(e.target.value);
}
​
function debounce (fn, delay) {
    let timer = null;
    return function () {
        clearTimeout(timer);
        timer = setTimeout(() => {
            fn.apply(this, arguments);
        }, delay)
    }
}
​
inp.addEventListener('input', debounce(oninput, 1000))

debounce 中传入两个参数[ 触发的事件函数,延迟的时间 ],大功告成了~~

节流

概念: 在执行事件时一段时间内只触发一次。

那我们怎么控制它在 一段时间内只触发一次 呢?我们可以理解为 降低频率,何为降低频率?就是一段时间内,如果触发多次事件(函数),但是我们只会保留一次,其他的不保留。实现它,就实现了 节流 的效果。

一段时间内只触发一次,我们可以想象成一个 阀门 ,一段时间开一次然后又关闭,一段时间开一次然后又关闭,如此的反复循环下去...

我们模拟一下点击按钮时的 如何 降低频率

<button class="btn">发送</button>

js 代码:

let btn = document.querySelector('.btn');
let flag = true;
function handlerClick (e) {
    if (flag) {
        flag = false;
        console.log(e.target.textContent);
    } 
}
​
btn.addEventListener('click', handlerClick);

这时,控制台只会打印一次,因为我们把阀门打开之后立马又关闭了,没有达到反复循环的效果,那我们应该怎么做呢? 我们可以加上一个定时器 setTimeout 帮助我们过一段时间后打开阀门。

假设是 1s 钟,我们修改一下代码:

let btn = document.querySelector('.btn');
let flag = true;
function handlerClick (e) {
    if (flag) {
        flag = false;
        console.log(e.target.textContent);
        
        setTimeout(() => {
            flag = true;
        }, 1000)
    } 
}
​
btn.addEventListener('click', handlerClick);

GIF 2022-4-11 22-52-10.gif

是不是有那感觉了,哈哈哈,太对了哥,哥太对~~

我们把代码封装一下吧。

// throttle.js

let btn = document.querySelector('.btn');
​
function handlerClick (e) {
    console.log(e.target.textContent);
}
​
function throttle (fn, delay) {
    let flag = true;
    return function () {
        if (flag) {
            flag = false;
            fn.apply(this, arguments);
​
            setTimeout(() => {
                flag = true;
            }, 1000)
        }
    }
}
​
btn.addEventListener('click', throttle(handlerClick, 1000));

throttle 中传入两个参数[ 触发的事件函数,延迟的时间 ],大功告成了~~

总结

以上就是本次分享的全部内容~~

如果觉得文章写得不错,对你有所启发的,请不要吝啬 点个 关注 并在 评论区 留下你宝贵的意见哦~~😃