内容简介:关注前端体验或性能优化的应该有听说过在短时间内多次触发同一个函数,只执行最后一次。举例:搭乘公交车的时候,陆续有不同的乘客上车,但师傅只会在最后一个乘客上车后才关门。
面试之手写防抖节流
关注前端体验或性能优化的应该有听说过 防抖
, 节流
。那么,什么是防抖节流呢?
防抖
概念
在短时间内多次触发同一个函数,只执行最后一次。
举例:搭乘公交车的时候,陆续有不同的乘客上车,但师傅只会在最后一个乘客上车后才关门。
效果演示
防抖前
防抖后
应用场景
-
表单输入验证
-
表单输入触发搜索 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才能再次获取。
效果演示
节流前
节流后
应用场景
-
编辑器语法校验
-
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函数也完成了。
总结
防抖和节流是两个在工作中很可能会遇到的问题,弄清楚其作用和原理对技能提升和面试都会有帮助。
参考
欢迎到前端学习打卡群一起学习~516913974
以上所述就是小编给大家介绍的《面试之手写防抖节流》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。