一、 引申
在项目中总会碰到一些因为事件频繁触发,导致 DOM 操作、资源加载等严重消耗资源行为。
1. window对象的resize、scroll事件
2. 拖拽时的mousemove事件
3. 射击游戏中的mousedown、keydown事件
4. 文字输入、自动完成的keyup事件
针对这些事件就出现了debounce和throttle两种解决办法。
二、函数节流(throttle)
规定在一个时间间隔内,只能触发一次函数。即使这个时间间隔内触发多次函数,也只有一次生效。
throttle (fn, interval){
let last = 0
return function() {
let cur = Date.now()
if (cur - last > interval) {
fn.apply(this, arguments)
last = cur
}
}
}
三、 函数去抖(debounce)
// 思路:在规定时间内未触发第二次,则执行,即在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。
在《JavaScript高级程序设计》一书有介绍函数去抖,里面封装了这样一个函数去抖函数:
function throttle(method, context) {
clearTimeout(methor.tId);
method.tId = setTimeout(function(){
method.call(context);
}, 1000);
}
它把定时器ID存为函数的一个属性。并且没有触发1s调用一次,而调用的时候就直接写
window.onresize = function(){
throttle(myFunc);
}
它就是利用为函数添加属性的方式增加定时器,但是可能会被修改,下面是我自己封装的一个使用闭包的去抖函数。高内聚低耦合
function debounce (fn, delay) {
let lastFn = null
// 利用闭包保存定时器
return function() {
let args = arguments
// 在规定时间内再次出发会先清除定时器后再重设定时器
clearTimeout(lastFunc)
lastFn = setTimeout(() => {
fn.apply(this, args)
}, delay)
}
}
function fn () {
console.log('防抖')
}
let debounceFn = debounce(fn, 1000) // 重要,需要将去抖函数指向内存中闭包位置
某DOM.addEventListener('scroll', function () { // 也可以改为其他任意方法
debounceFn()
})
总结
- 函数去抖和函数节流都是防止某一时间频繁触发,但是这两兄弟之间的原理却不一样。
- 函数去抖是某一段时间内只执行一次,而函数节流是间隔时间执行。