定义
在JS里,有一些事件是很容易频繁触发的,比如窗口的resize
、scroll
、鼠标的onmousemove
等操作,在事件频繁触发的过程中,不可避免的导致频繁执行触发事件中的函数。为了防止这种情况的发生,主流的解决方案有两种,防抖(debounce
)和节流(throttle)
频繁执行情况
var num = 1;
var moveCntent = document.getElementById('example')
function count(){
moveCntent.innerHTML++;
}
moveCntent.onmousemove = count
效果如下:
可以明显的看到,count 函数执行的非常频繁,假如现在我们count函数里执行的是一个Ajax请求,那么问题就会非常严重了。
防抖
函数防抖就是在一段时间(n毫秒)触发或调用函数时,只执行一次; 也可以理解为触发n毫秒之后才会调用一次。
防抖函数的写法主要有两种,非立即执行版本和立即执行版本。
非立即执行版
var num = 1;
var moveCntent = document.getElementById('example')
function count(){
moveCntent.innerHTML++;
}
moveCntent .onmousemove = count
function debounce(fn,delay){
var timer;
return function(){
var _this = this;
var args = arguments;
if(timer) clearTimeout(timeout);
timer = setTimeout(function(){
fn.apply(_this,args)
},delay)
}
}
moveCntent.onmousemove = debounce(count,1000)
原理是维护一个计时器,规定在delay时间后触发函数,但是在delay时间内再次触发的话,就会取消之前的计时器而重新设置。这样一来,只有最后一次操作能被触发。
效果如下:
在触发事件1秒后才执行,如果在触发事件的一秒内又触发了事件,则重新计算函数执行时间
立即执行版
function debounce(fn,delay){
var timer;
return function(){
var _this = this;
var args = arguments;
if(timer){
clearTimeout(timer);
}
if(!timer){
fn.apply(_this,args);
}
timer = setTimeout(function(){
timer = null;
},delay);
};
}
立即执行版本和非例行版本的区别是:
- 立即执行版本:触发事件后函数立即执行,然后n秒内不触发时间才会继续执行
- 非立即执行版本:触发事件后函数不会立即执行,而是在n秒回才会执行
节流
函数节流,就是指连续触发的事件在n秒钟只执行一次函数。降低函数的执行频率,对于函数节流,通常也也有两种方式实现,分别是时间戳版和定时器版
时间戳版
function throttle(fn,delay){
var previous = 0;
return function(){
var now = Date.now();
var _this = this;
var args = arguments;
if(now - previous > delay){
fn.apply(_this,args);
previous = now;
}
};
}
moveCntent.onmousemove = throttle(count,1000)
当高频事件触发时,第一次会立即执行,而后再怎么频繁地触发事件,也都是每delay时间才执行一次。
效果如下:
持续触发事件的过程中,函数会立即执行,并且每一秒执行一次
定时器版
function throttle(fn,delay){
var timer;
return function(){
var _this = this;
var args = arguments;
if(!timer){
timer = setTimeout(function(){
timer = null;
fn.apply(_this,args);
},delay);
}
};
}
在持续触发事件的过程中,函数不会立即执行,并且每一秒执行一次,停止触发事件后,还会再执行一次
效果如下:
时间戳版本和定时器版本的区别是:
- 时间戳版本:触发事件后函数立即执行,每n秒执行一次
- 定时器版本:触发事件后函数不会立即执行,每n秒执行一次,停止触发后还会执行一次
总结
函数防抖:将几次操作合并为一此操作进行。原理是维护一个计时器,规定在delay时间后触发函数,但是在delay时间内再次触发的话,就会取消之前的计时器而重新设置。这样一来,只有最后一次操作能被触发。
函数节流:使得一定时间内只触发一次函数。原理是通过判断是否到达一定时间来触发函数。
区别: 函数节流不管事件触发有多频繁,都会保证在规定时间内一定会执行一次真正的事件处理函数,而函数防抖只是在最后一次事件后才触发一次函数。 比如在页面的无限加载场景下,我们需要用户在滚动页面时,每隔一段时间发一次 Ajax 请求,而不是在用户停下滚动页面操作时才去请求数据。这样的场景,就适合用节流技术来实现。