来,先说概念:
防抖:
防抖函数指的是某个函数在某段时间内,无论触发了多少次回调,都只执行最后一次。假如我们设置了一个等待时间 3 秒的函数,在这 3 秒内如果遇到函数调用请求就重新计时 3 秒,直至新的 3 秒内没有函数调用请求,此时执行函数,不然就以此类推重新计时。
触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间。
节流:
函数节流指的是某个函数在一定时间间隔内(例如 3 秒)只执行一次,在这 3 秒内 无视后来产生的函数调用请求,也不会延长时间间隔。3 秒间隔结束后第一次遇到新的函数调用会触发执行,然后在这新的 3 秒内依旧无视后来产生的函数调用请求,以此类推。
高频事件触发,但在n秒内只会执行一次,所以节流会稀释高频函数的执行频率
相同点:在一定时间内,调用多次,但是只执行一次。
区别 | 防抖 | 节流 |
|---|---|---|
| 执行时间是否会延长 | 新的调用进来,时间会延长,从最后一次调用开始计时 | 不会,从第一次调用开始计时 |
| 最终执行的调用 | 是最后一次 | 是第一次 |
防抖:举一个这样的例子,也是真正的业务场景。
这是一个表单,我需要在银行卡号的onChange时间中取查询所属行,需求原因,不能放在onBlur中。
可以确定的是不能在每次的onChange事件中去查询,这就是一个典型的防抖的Demo。
直接来一个实现吧。
function debounce(fn, wait = 50) {
// 通过闭包缓存一个定时器 id let timer = null;
// 将 debounce 处理结果当作函数返回
// 触发事件回调时执行这个返回函数
return function(...args) { // 如果已经设定过定时器就清空上一次的定时器
if (timer) clearTimeout(timer) // 开始设定一个新的定时器,定时器结束后执行传入的函数 fn
timer = setTimeout(() => {
fn.apply(this, args)
}, wait)
}}// DEMO
const betterFn = debounce(() => console.log('fn 防抖执行了'), 1000)
function debounce(fn, wait = 50) { // 通过闭包缓存一个定时器 id let timer = null; // 将 debounce 处理结果当作函数返回 // 触发事件回调时执行这个返回函数 // 如果已经设定过定时器就清空上一次的定时器 if (timer) clearTimeout(timer) // 开始设定一个新的定时器,定时器结束后执行传入的函数 fn timer = setTimeout(() => { }, wait) }}// DEMO// 执行 debounce 函数返回新函数// 停止滑动 1 秒后执行函数 () => console.log('fn 防抖执行了') |
节流函数:
// wait 是时间间隔const throttle = (fn, wait = 50) => { // 上一次执行 fn 的时间 let previous = 0 // 将 throttle 处理结果当作函数返回 // 获取当前时间,转换成时间戳,单位毫秒 let now = +new Date() // 将当前时间和上一次执行函数的时间进行对比 // 大于等待时间就把 previous 设置为当前时间并执行函数 fn if (now - previous > wait) { previous = now } }}// 执行 throttle 函数返回新函数// 每 10 毫秒执行一次 betterFn 函数,但是只有时间差大于 1000 时才会执行 fnsetInterval(betterFn, 10)