由于最近看到了简书上关于这个的文章,想到原来在coding上看过这方面的文章所以记录总结一下。
throttle (_.throttle(func, wait, options)
)
这个函数的作用就是防止多次频繁的调用,规定在wait左右只能执行一次,目的是限制执行频率。
用法如下:
var throttled = _.throttle(updatePosition, 100);
$(window).scroll(throttled);
这样在滚动的时候就可以控制一下发生的频率。
underscore的源码如下:
_.throttle = function(func, wait, options) {
var timeout, context, args, result;
var previous = 0;
if (!options) options = {};
var later = function() {
// 如果options.leading === false在这里重新设置 previous
previous = options.leading === false ? 0 : _.now();
timeout = null;
result = func.apply(context, args);
if (!timeout) context = args = null;
};
var throttled = function() {
var now = _.now();
if (!previous && options.leading === false) previous = now;
var remaining = wait - (now - previous);
context = this;
// 但是args每次都是最新的
args = arguments;
// 距离上次的时间已经大约wait,直接运行
if (remaining <= 0 || remaining > wait) {
if (timeout) {
clearTimeout(timeout);
timeout = null;
}
previous = now;
result = func.apply(context, args);
if (!timeout) context = args = null;
// 这个是options.leading === false的时候做第一次调用
// 或者wait之内再调用的时候
} else if (!timeout && options.trailing !== false) {
timeout = setTimeout(later, remaining);
}
return result;
};
throttled.cancel = function() {
clearTimeout(timeout);
previous = 0;
timeout = context = args = null;
};
return throttled;
};
原理其实就是设置一个timer来控制发生的频率,用高阶函数来实现一个闭包,每次调用args都被赋予最新的值,最后调用fun的时候肯定是最新的args。保证一个wait左右只执行一个fn。
然后我们来看看的他的亲兄弟debounce
,看似很相似,其实应用场景是不太一样的。
它的作用是拖延执行fun wait时间,wait内又调用fun那么再拖延wait时间,最后没有wait内调用那么执行,目的多次频繁的调用合并为一次执行,不需要中间的过程。
应用场景如 form 的提交,防止两次频繁的点击。或者,markdown编辑同时渲染显示。
var lazyLayout = _.debounce(calculateLayout, 300);
$(window).resize(lazyLayout);
这个应用只需要最后的size就好,不需要中间的多余计算。
源码如下:
_.debounce = function(func, wait, immediate) {
var timeout, result;
var later = function(context, args) {
timeout = null;
if (args) result = func.apply(context, args);
};
var debounced = restArgs(function(args) {
var callNow = immediate && !timeout;
if (timeout) clearTimeout(timeout);
if (callNow) {
timeout = setTimeout(later, wait);
result = func.apply(this, args);
} else if (!immediate) {
timeout = _.delay(later, wait, this, args);
}
return result;
});
debounced.cancel = function() {
clearTimeout(timeout);
timeout = null;
};
return debounced;
};
每次调用都清掉先前的timeout,推移一个timeout。
如果immediate为true的话,立刻调用,然后wait内不可以再次调用,
可以用于form提交。
网友评论