防抖和节流:是优化高频率执行代码的手段。
目的:节约浏览器、服务器的性能。
主要方式:减少函数执行的次数。
函数防抖(debounce)
函数防抖:事件被触发,等待n秒后再执行回调,如果在这n秒内又被触发,则重新计数。
防抖的目的:目的是为了让一定时间段的连续的函数调用,只让其执行一次。
我们来举一个上电梯的例子: 电梯总是在进出人(监听事件)之后的5秒关门(执行方法), 如果5秒钟之内又有人进出, 则重新开始计时, 直到最后一个进出电梯的事件发生5秒钟之后执行关门。
函数节流(throttle)
函数节流:规定在一个单位时间内,只能有一次触发事件的回调函数执行,如果在同一个单位时间内某某被触发多次,则只有一次能生效。
节流的目的:是让一个函数不要执行太频繁,减少一些过快的调用来节流。
常用到的场景
- 返回顶部问题
- 搜索框input事件,例如要支持输入实时搜索可以使用节流方案(间隔一段时间就必须查询相关内容),或者实现输入间隔大于某个值(如500ms),就当做用户输入完成,然后开始搜索,具体使用哪种方案要看业务需求。
- 页面resize事件,常见于需要做页面适配的时候。需要根据最终呈现的页面情况进行dom渲染(这种情形一般是使用防抖,因为只需要判断最后一次的变化情况)
/* debounce */
function debounce(fn, wait) {
var timer = null;
return function () {
var context = this;
var args = arguments;
// 如果在n秒内还有定时未执行,则删除之前的定时任务
if (timer) {
clearTimeout(timer);
timer = null;
}
// 重新设定定时任务
timer = setTimeout(function () {
fn.apply(context, args);
}, wait);
}
}
var fn = function () {
console.log('debounce function doing...');
}
// 第一次在1500ms后触发,之后每1000ms触发一次
setInterval(debounce(fn, 500), 1000);
// 不会触发一条
setInterval(debounce(fn, 2000), 1000);
/* throttle */
function throttle(fn, gapTime) {
var _lastTime = null;
var timer = null;
return function () {
var _nowTime = new Date().getTime();
var context = this;
var args = arguments;
if (!_lastTime) {
_lastTime = new Date().getTime();
fn.apply(context, args);
} else if (_nowTime - _lastTime < gapTime) {
if (timer) {
clearTimeout(timer);
timer = null;
}
timer = setTimeout(function () {
// 这个定时函数一直都没有执行,因为当周期时间(如10ms)小于定时时间(如1000ms)时
// 总是在不停的clearTimeout和setTimeout,所以就永远进入不到这个函数体
// 除非对最外面的周期函数使用clearTimeout,那么才会执行一次这个函数体
_lastTime = new Date().getTime();
fn.apply(context, args)
}, gapTime);
} else {
_lastTime = new Date().getTime();
fn.apply(context, args);
}
}
}
var fn = function () {
console.log('throttle function doing...');
}
test = setInterval(throttle(fn, 1000), 10)
clearTimeout(test);