高频面试题之防抖节流及代码实现

2,648 阅读2分钟

理论

函数节流:一个函数执行一次后,只有大于设定的周期后才会执行第二次;需要频繁触发函数,处于优化性能角度,在规定时间内只让函数触发一次,后面不生效

函数防抖:一个需要频繁触发的函数,在规定时间内,只让最后一次生效,前面的无效

区别在于:函数节流是周期性进行触发,也就是规定时间内触发的次数也是固定的;函数防抖则不固定,会被打断,打断就需要重新积蓄时长。 在这里插入图片描述 打王者的时候, 技能用完需要一段时间冷却,这就是节流;

但是你回城被打断了就得重新回城,这就跟防抖一个道理。

实践

节流函数 throttle (不带参数,带参数)

防抖函数 debounce (不带参数,带参数)

节流函数 throttle

节流函数 throttle有两种实现形式,分别是时间戳定时器

简单实现一下节流函数 throttle (先不考虑传参)

function throttle(fn, delay) {
    let start = 0
    return () => {
        let end = Date.now()
        if (end - start > delay) {
            //修正this指向
            fn.call(this)
            //注意同步时间
            start = end
        }
    }
}

节流函数使用,滚动屏幕测试,设置一下样式使得出现滚动条

html,
body {
 height: 500%;
}
document.onscroll = throttle(_ => {
 console.log(`触发${Date.now()}`)
}, 200)

在这里插入图片描述 由截图可以看出时间间距在200以上,节流成功

现在来看看节流的传参

function throttle(fn, delay) {
    let start = 0
    return (...args) => {
        let end = Date.now()
        if (end - start > delay) {
            //修正this指向
            fn.apply(this, args)
            //注意同步时间
            start = end
        }
    }
}
let inputs = document.getElementById('inputs')
let fn = throttle(e => {
    console.log(`触发${Date.now()},输入的值为${e.target.value}`)
}, 200)
//监听input输入事件
inputs.addEventListener('input', fn)

html部分写个输入框

<input id="inputs" type="text">

在这里插入图片描述 可以看出在我狂敲1的操作下,被节流了几次

与不传参的区别在于: 注意看到传参是时候修改this指向的从call变成apply,便于传入多个参数,接收参数的地方用三个点...进行展开

上面使用的是时间戳的形式实现节流,还有一个方式是利用定时器实现节流函数

function throttle(fn, delay) {
    let timer = null;
    let flag = true; //中间媒介   
    return (...args) => {
        if (!flag) return;
        clearTimeout(timer);
        flag = false; //标志flag为false,使得不会影响后面的执行
        timer = setTimeout(() => {
            fn.apply(this, args);
            flag = true;
        }, delay)
    }
}

利用标志flag为中间媒介,当flag为true时候,可以进入函数;当flag为false,不可以进入函数,因此不会影响后面的执行


现在我们继续来看防抖函数,也就是需要蓄能的才能回城的函数

防抖函数 debounce

需要一个定时器进行辅助,在规定的时间内,如果没有被打断,则可以执行函数 先来一个不传参数的防抖函数

function debounce(fn, delay) {
    let timer = null
    //清除定时器
    return function () {
        clearTimeout(timer)
        //重新设置定时器
        timer = setTimeout(()=> {
            fn.apply(this)
        }, delay)
    }
}

利用按钮点击进行测试

document.getElementById('btn').onclick = debounce(_ => {
 console.log(`触发${Date.now()}`)
}, 200)

html

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

由截图可以看出,多次点击,只有时间超过200的间隔才有生效,在疯狂点击(点击时差200内)情况下,会持续没有输出效果,也就是被打断多次,无法执行函数

现在可以进行传递参数,原理和节流的传参方式一致

function debounce(fn, delay) {
    let timer = null
    return (...args) => {
        clearTimeout(timer);
        timer = setTimeout(() => {
            fn.apply(this, args);
        }, delay)
    }
}
let inputs = document.getElementById("inputs")
let fn = debounce((e) => {
    console.log(e.target.value)
}, 200)
//监听input事件
inputs.addEventListener("input", fn)

在这里插入图片描述 由上图可知,疯狂敲1会一直积蓄,函数不执行,稍微停顿才能执行输出,实现防抖的效果

总结

节流函数:一个函数执行一次后,只有大于设定的周期后才会执行第二次;类似游戏中的技能用完需要一段时间冷却。实际可以应用于获取短信验证码的按钮。

防抖函数:一个需要频繁触发的函数,在规定时间内,只让最后一次生效,前面的无效;类似游戏中你回城被打断了就得重新回城。实际可以应用于搜索框。

欢迎关注我的个人公众号,写文不易,有用的话请点个赞,Thanks♪(・ω・)ノ

在这里插入图片描述
在这里插入图片描述

本文使用 mdnice 排版