debounce函数所做的事情是:强制一个函数在某个连续的时间段内只执行一次,哪怕他本来会被调用多次,我们希望在用户停止某个操作一段时间之后才执行相应的监听函数,而不是在用户操作的过程当中,浏览器触发多少事件,就执行多少监听函数。
//弹跳函数
function debounce(fn,delay){
var timer
return function(){
var _this = this;
var args = arguments;
//每次这个返回函数被调用,就清楚定时器,保证fn不被执行
clearTimeout(time);
//当返回的函数被最后一次调用(用户停止了某个连续动作),延迟delay毫秒后执行fn
timer = setTimeout(function(){
fn.apply(_this,args);
},delay)
}
}
//调用
$(document).on('mouvemove', debounce(function(e) {
// 代码
}, 250))
原理:debounce返回一个闭包,这个闭包会被连续平凡的调用,但在闭包内部却显示了原始函数fn的执行,强制fn只在连续操作停止后执行一次。
使用场景:
1 比如,在某个 3s 的时间段内连续地移动了鼠标,浏览器可能会触发几十(甚至几百)个 mousemove 事件,不使用 debounce 的话,监听函数就要执行这么多次;如果对监听函数使用 100ms 的“去弹跳”,那么浏览器只会执行一次这个监听函数,而且是在第 3.1s 的时候执行的。
2 根据用户的输入实时向服务器发 ajax 请求获取数据。我们知道,浏览器触发 key* 事件也是非常快的,即便是正常人的正常打字速度,key* 事件被触发的频率也是很高的。以这种频率发送请求,一是我们并没有拿到用户的完整输入发送给服务器,二是这种频繁的无用请求实在没有必要。
更合理的处理方式是,在用户“停止”输入一小段时间以后,再发送请求。那么 debounce 就派上用场了:
$('input').on('keyup', debounce(function(e) {
// 发送 ajax 请求
}, 300))
Throttle就是固定函数执行的速率,即所谓的“节流”。
/**
*
* @param fn {Function} 实际要执行的函数
* @param delay {Number} 执行间隔,单位是毫秒(ms)
*
* @return {Function} 返回一个“节流”函数
*/
function throttle(fn, threshhold) {
// 记录上次执行的时间
var last
// 定时器
var timer
// 默认间隔为 250ms
threshhold || (threshhold = 250)
// 返回的函数,每过 threshhold 毫秒就执行一次 fn 函数
return function () {
// 保存函数调用时的上下文和参数,传递给 fn
var context = this
var args = arguments
var now = +new Date()
// 如果距离上次执行 fn 函数的时间小于 threshhold,那么就放弃
// 执行 fn,并重新计时
if (last && now < last + threshhold) {
clearTimeout(timer)
// 保证在当前时间区间结束后,再执行一次 fn
timer = setTimeout(function () {
last = now
fn.apply(context, args)
}, threshhold)
// 在时间区间的最开始和到达指定间隔的时候执行一次 fn
} else {
last = now
fn.apply(context, args)
}
}
}
如果还是不能完全体会 debounce
和 throttle
的差异,可以到 这个页面 看一下两者可视化的比较。
debounce 强制函数在某段时间内只执行一次,throttle 强制函数以固定的速率执行。在处理一些高频率触发的 DOM 事件的时候,它们都能极大提高用户体验。
原文地址:https://blog.csdn.net/redtopic/article/details/69396722