面试之手写防抖节流

面试之手写防抖节流
关注前端体验或性能优化的应该有听说过防抖,节流。那么,什么是防抖节流呢?

防抖
概念
在短时间内多次触发同一个函数,只执行最后一次。

举例:搭乘公交车的时候,陆续有不同的乘客上车,但师傅只会在最后一个乘客上车后才关门。

效果演示
防抖前

01

防抖后

02

应用场景
表单输入验证

表单输入触发搜索 ajax

resize/scroll/touch/mouseove 事件

实现
简单版本

function debounce(fn, wait = 1000) {
let timer = null;

return function debounced(…args) {
// 重置计时器
if (timer) clearTimeout(timer);

// 新计时器
timer = setTimeout(() => {
  fn(...args);
  timer = null;
}, wait);

};
}
可以看出debounce函数的实现原理就是通过计时器延迟函数执行,短时间内再次触发时重置并添加新计时器。此时的输出函数还有个缺陷,就是this指向global,我们需要让它指向原本指向的变量。

function debounce(fn, wait = 1000) {
let timer = null;

return function debounced(…args) {
// 重置计时器
if (timer) clearTimeout(timer);

// 新计时器
timer = setTimeout(() => {
  fn.apply(this, ...args);
  timer = null;
}, wait);

};
}
现在我们实现了一个简单的防抖函数。有时候我们会要求函数在第一次触发立即执行,我们来为它添加个参数。

function debounce(fn, wait = 1000, immediate = false) {
let timer = null;

return function debounced(…args) {
// 重置计时器
if (timer) clearTimeout(timer);

// 首次立即执行
if (immediate && !timer) {
  fn.apply(this, ...args);

  timer = setTimeout(() => {
    timer = null;
  }, wait);

  return;
}

// 新计时器
timer = setTimeout(() => {
  fn.apply(this, ...args);
  timer = null;
}, wait);

};
}
我们还可以为其添加取消的功能。

function debounce(fn, wait = 1000, immediate = false) {
let timer = null;

function debounced(…args) {
// 重置计时器
if (timer) clearTimeout(timer);

// 首次立即执行
if (immediate && !timer) {
  fn.apply(this, ...args);

  timer = setTimeout(() => {
    timer = null;
  }, wait);

  return;
}

// 新计时器
timer = setTimeout(() => {
  fn.apply(this, ...args);
  timer = null;
}, wait);

}

debounced.cancel = () => {
clearTimeout(timer);
timer = null;
};

return debounced;
}
此时一个功能完备的debounce函数就完成了。

节流
概念
多次触发同一个函数,同一段时间内只执行一次。

举例:获取验证码很多都会限制 60s 的时间,在 60s 内再次获取验证码是无效,只能获取一次。下个60s才能再次获取。

效果演示
节流前

01

节流后

03

应用场景
编辑器语法校验

resize/scroll/touch/mouseove 事件

表单输入联想

实现
简单版本

function throttle(fn, wait = 1000) {
let previous = 0;

const throttled = (…args) => {
const now = +new Date();

if (now - previous > wait) {
  fn.apply(this, args);
  previous = now;
}

};

return throttled;
}
可以看出节流的主要原理就是利用时间差(当前和上次执行)来过滤中间过程触发的函数执行。我们现在为其添加参数来控制是否在开始时会立即触发一次,及最后一次触发是否执行。

function throttle(fn, wait, options = { leading: true, trailing: false }) {
let timer;
let previous = 0;

const { leading, trailing } = options;

const throttled = function (…args) {
const now = +new Date();

if (leading === false && !previous) previous = now;
if (timer) clearTimeout(timer);

if (now - previous > wait) {
  fn.apply(this, args);
  previous = now;
} else if (trailing) {
  // 更新timer
  timer = setTimeout(() => {
    fn.apply(this, args);
    previous = 0;
    timer = null;
  }, wait);
}

};

return throttled;
}
我们还可以为其添加取消的功能。

function throttle(fn, wait, options = { leading: true, trailing: false }) {
let timer;
let previous = 0;

const { leading, trailing } = options;

const throttled = function (...args) {
    const now = +new Date();

    if (leading === false && !previous) previous = now;
    if (timer) clearTimeout(timer);

    if (now - previous > wait) {
        fn.apply(this, args);
        previous = now;
    } else if (trailing) {
        // 更新timer
        timer = setTimeout(() => {
            fn.apply(this, args);
            previous = 0;
            timer = null;
        }, wait);
    }
}
throttled.cancel = () => {
    clearTimeout(timer);
    timer = null;
    previous = 0;
}


return throttled;

}
此时一个功能完备的throttle函数也完成了。

总结
防抖和节流是两个在工作中很可能会遇到的问题,弄清楚其作用和原理对技能提升和面试都会有帮助。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值