本文最后更新于:2022年9月1日 凌晨
防抖函数和节流函数的定义、具体实现、应用场景和异同点
防抖节流函数
是什么
防抖函数(debounce):n 秒后在执行该事件,若在 n
秒内被重复触发,则重新计时
节流函数(throttle):n 秒内只运行一次,若在 n
秒内重复触发,只有一次生效
为什么要防抖节流函数
本质上是优化高频率执行代码的一种手段,对浪费资源的事件采取限制调用次数的限制
常见应用场景
防抖在连续的事件,只需触发一次回调的场景有:
- 搜索框搜索输入。只需用户最后一次输入完,再发送请求
- 手机号、邮箱验证输入检测
- 窗口大小
resize
。只需窗口调整完成后,计算窗口大小。防止重复渲染。
节流在间隔一段时间执行一次回调的场景有:
- 滚动加载,加载更多或滚到底部监听
- 搜索框,搜索联想功能
代码实现
防抖
1 2 3 4 5 6 7 8 9 10 11 12 13
| function debounce(func, wait) { let timeout;
return function () { let context = this; let args = arguments;
clearTimeout(timeout); timeout = setTimeout(function () { func.apply(context, args); }, wait); }; }
|
防抖如果需要立即执行,可加入第三个参数用于判断,实现如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| function debounce(func, wait, immediate) { let timeout;
return function () { let context = this; let args = arguments;
if (timeout) clearTimeout(timeout); if (immediate) { let callNow = !timeout; timeout = setTimeout(function () { timeout = null; }, wait); if (callNow) { func.apply(context, args); } } else { timeout = setTimeout(function () { func.apply(context, args); }, wait); } }; }
|
节流
利用定时器实现节流函数:
1 2 3 4 5 6 7 8 9 10 11
| function throttled(fn, delay = 500) { let timer = null; return function (...args) { if (!timer) { timer = setTimeout(() => { fn.apply(this, args); timer = null; }, delay); } }; }
|
利用时间戳实现节流函数,时间会立即执行,停止触发后没办法再次执行:
1 2 3 4 5 6 7 8 9 10
| function throttled(fn, delay = 500) { let oldTime = Date.now(); return function (...args) { let newTime = Date.now(); if (newTime - oldTime >= delay) { fn.apply(null, args); oldTime = Date.now(); } }; }
|
将时间戳写法的特性与定时器写法的特性相结合,更精确:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| function throttled(fn, delay) { let timer = null; let startTime = Date.now(); return function () { let curTime = Date.now(); let remaining = delay - (curTime - startTime); let context = this; let args = arguments; clearTimeout(timer); if (remaining <= 0) { fn.apply(context, args); startTime = Date.now(); } else { timer = setTimeout(fn, remaining); } }; }
|
总结
相同点
- 都可以通过使用
setTimeout
实现
- 目的都是,降低回调执行频率。节省计算资源
不同点
在一段连续操作结束后,处理回调,利用
clearTimeout 和 setTimeout 实现 |
在一段连续操作中,每一段时间只执行一次,频率较高的事件中使用来提高性能 |
希望一定时间连续触发的事件只在最后执行一次 |
希望一定时间连续触发的事件一段时间内只执行一次 |
参考文章
面试官:什么是防抖和节流?有什么区别?如何实现?
彻底弄懂函数防抖和函数节流
- SegmentFault 思否