一、目的:防止函数被无意义高频调用
二、理解:
1、防抖(debounce)
本质:函数在特定的时间内不再被调用后执行
原理:设置一个定时器,如果在设定的时间间隔内事件再次触发,就会清除上一次的定时器并重新设置和计时,直到指定时间间隔内没有再次触发,才会执行函数
缺点:如果事件在规定的时间间隔内被不断的触发,则调用方法会被不断的延迟
使用场景:文本框输入搜索(连续输入时避免多次请求接口)
个人通俗理解:事件连续触发,只执行最后一次回调函数
示例如下:
function showTop () {
var scrollTop = document.body.scrollTop ||document.documentElement.scrollTop;
console.log('滚动条位置:' + scrollTop);
}
function debounce(fn, delay) {
let timer = null; //借助闭包
return function () {
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(fn, delay)
}
}
window.onscroll=debounce(showTop,200)
2、节流(throttle)
本质:确保函数特定的时间内至多执行一次
原理:用时间戳来判断是否已到回调该执行时间,记录上次执行的时间戳,然后每次触发 scroll 事件执行回调,回调中判断当前时间戳距离上次执行时间戳的间隔是否已经到达 规定时间段,如果是,则执行,并更新上次执行的时间戳
使用场景:resize、scroll、mousemove等事件触发监听
个人通俗理解:事件触发,函数执行,一定时间内函数无法再次执行
示例如下:
function showTop () {
var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
console.log('滚动条位置:' + scrollTop);
}
function throttle(fn,delay){
let valid = true;
return function() {
//
if(!valid){
return false
}
valid = false;
setTimeout(() => {
fn();
valid = true;
}, delay)
}
}
请注意,节流函数并不止上面这种实现方案,例如可以完全不借助setTimeout,可以把状态位换成时间戳,然后利用时间戳差值是否大于指定间隔时间来做判定。也可以直接将setTimeout的返回的标记当做判断条件判断当前定时器是否存在,如果存在表示还在冷却,并且在执行fn之后消除定时器表示激活,原理都一样
三、总结
总结:
函数防抖:将多次操作合并为一次操作进行。原理是维护一个计时器,规定在delay时间后触发函数,但是在delay时间内再次触发的话,就会取消之前的计时器而重新设置。这样一来,只有最后一次操作能被触发。
函数节流:使得一定时间内只触发一次函数。原理是通过判断是否有延迟调用函数未执行。
区别: 函数节流不管事件触发有多频繁,都会保证在规定时间内一定会执行一次真正的事件处理函数,而函数防抖只是在最后一次事件后才触发一次函数。 比如在页面的无限加载场景下,我们需要用户在滚动页面时,每隔一段时间发一次 Ajax 请求,而不是在用户停下滚动页面操作时才去请求数据。这样的场景,就适合用节流技术来实现。
本文参考自:https://segmentfault.com/a/1190000018428170和https://www.jianshu.com/p/3d3f62b9d0ad和https://blog.csdn.net/zuorishu/article/details/93630578