防抖与节流的定义
防抖与节流都是用来控制某个行为(通常是一个函数)在特定时间内执行多少次的技巧,两者极为相似,但又有细微区别。
-
防抖是限制某一行为在达到特定时间间隔后执行一次。如果特定时间间隔还没有达到又触发了该行为,就会重新计算间隔时间。实则就是等连续频繁的操作结束后,再等待特定时间执行一次函数。
-
节流是限制某一行为在特定的时间内至多执行一次。如果在特定时间内重复触发,将不会像防抖一样重新计算间隔时间,也不会重复执行函数,而是在特定时间结束后执行一次。实则是在触发函数行为的特定时间内只允许执行一次函数。
防抖与节流实用的场景
防抖:
- 每次 resize/scroll 完成后触发统一事件
- 文本框输入的验证(在连续输入文字的时候,在输入停止后校验)
function fun(){
console.log('onresize')
}
function debounce(method,context){
clearTimeout(method.timer);
method.timer = setTimeout(function(){
method.call(context);
},1000);
}
window.onresize = function(){
debounce(fun,window);
}
本例子在浏览器窗口改变后一秒钟 打印出 onresize,如果是一直挪动改变浏览器窗口,也会等停止挪动后一秒再打印 出onresize。
另外一种防抖的封装函数如下:
const debounce = (fn: () => void, delay: number) => {
const timerRef = null
return new Proxy(fn, {
apply(target, ctx, args) {
if (timerRef) {
clearTimeout(timerRef)
timerRef = null
}
timerRef = setTimeout(() => Reflect.apply(target, ctx, args), delay)
},
})
}
节流:
- DOM 元素的拖拽功能实现(mousemove)
- 射击游戏的 mousedown/keydown 事件(单位时间只能发射一颗子弹)
- 计算鼠标移动的距离(mousemove)
- Canvas 模拟画板功能(mousemove)
- 搜索联想(keyup)
- 监听滚动事件判断是否到页面底部自动加载更多
ul { border: 1px solid red; }
li { padding: 10px; }
<ul id="throttle">
<li>测试数据123456789</li>
<li>测试数据123456789</li>
<li>测试数据123456789</li>
<li>测试数据123456789</li>
<li>测试数据123456789</li>
<li>测试数据123456789</li>
<li>测试数据123456789</li>
<li>测试数据123456789</li>
<li>测试数据123456789</li>
………
</ul>
window.onload = function(){
let i = 1,
canRun = true;
window.addEventListener('scroll', function(){
if(!canRun){
return;
}
canRun = false;
setTimeout( function () {
console.log(`函数节流${i++}`);
canRun = true;
}, 2000)
})
}
如上例子 在首次触发后的2秒内滚动任意次数,只会打印一次;如果从开始一直滚动,会在从第一滚动开始每间隔2秒后打印出 ‘函数节流…’。
另外一种节流的封装函数如下:
const throttle = (fn: () => void, interval: number) => {
let startTime = 0
return new Proxy(fn, {
apply(target, ctx, args) {
const now = new Date().getTime()
if (now - startTime > interval) {
startTime = now
return Reflect.apply(target, ctx, args)
}
}
})
}
示例代码参考: 函数防抖与函数节流
可扩展阅读: