防抖和节流
1、函数防抖(debounce)
触发高频事件后指定时间内函数只会执行一次,如果在指定时间内高频事件再次被触发,则重新计算时间
实现方法
var debounce = function(fn, delayTime) {
var timeId;
return function () {
var context = this, args = arguments;
timeId && clearTimeout(timeout);
timeId = setTimeout(function {
fn.apply(context, args);
}, delayTime)
}
}
执行debounce函数之后会返回一个新的函数,通过闭包的形式,维护一个变量timeId,每次执行该函数的时候会结束之前的延迟操作,重新执行setTimeout方法,也就实现了上面所说的指定的时间内多次触发同一个事件,会合并执行一次。
1、上述代码中arguments只会保存事件回调函数中的参数,譬如:事件对象等,并不会保存fn、delayTime
2、使用apply改变传入的fn方法中的this指向,指向绑定事件的DOM元素。
2.函数节流(throttle)
高频事件触发,但在n秒内只会执行一次,即触发事件间隔大于等于指定的时间才会执行回调函数。所以节流会稀释函数的执行频率。
实现方法
1、时间戳
var throttle = (fn, delayTime) => {
var _start = Date.now();
return function () {
var _now = Date.now(), context = this, args = arguments;
if(_now - _start >= delayTime) {
fn.apply(context, args);
_start = Date.now();
}
}
}
通过比较两次时间戳的间隔是否大于等于我们事先指定的时间来决定是否执行事件回调
2、定时器
var throttle = function (fn, delayTime) {
var flag;
return function () {
var context = this, args = arguments;
if(!flag) {
flag = setTimeout(function () {
fn.apply(context, args);
flag = false;
}, delayTime);
}
}
}
1、使用时间戳方式,页面加载的时候就会开始计时,如果页面加载时间大于我们设定的delayTime,第一次触发事件回调的时候便会立即fn,并不会延迟。如果最后一次触发回调与前一次触发回调的时间差小于delayTime,则最后一次触发事件并不会执行fn;
2、使用定时器方式,我们第一次触发回调的时候才会开始计时,如果最后一次触发回调事件与前一次时间间隔小于delayTime,delayTime之后仍会执行fn。
我们考虑把这两种方式结合起来,便会在第一次触发事件时执行fn,最后一次与前一次间隔比较短,delayTime之后再次执行fn。
var throttle = function (fn, delayTime) {
var flag, _start = Date.now();
return function () {
var context = this,
args = arguments,
_now = Date.now(),
remainTime = delayTime - (_now - _start);
if(remainTime <= 0) {
fn.apply(this, args);
} else {
setTimeout(function () {
fn.apply(this, args);
}, remainTime)
}
}
}
通过上面的分析,可以很明显的看出函数防抖和函数节流的区别:
频繁触发事件时,函数防抖只会在最后一次触发事件只会才会执行回调内容,其他情况下会重新计算延迟事件,而函数节流便会很有规律的每隔一定时间执行一次回调函数。