节流throttle
设定一个时间间隔,某个频繁触发的函数,在这个时间间隔内只会执行一次。也就是说,这个频繁触发的函数会以一个固定的周期执行。
高频触发的函数每隔一个时间段执行执行,并且最后一次触发时也执行
适用场景:
- 鼠标不断点击触发,mousedown(单位时间内只触发一次)
- 监听滚动事件,比如是否滑到底部自动加载更多,用 throttle 来判断
时间戳版本
function throttle(func, delay){
let prev = Date.now();
return function(){
const context = this;
const args = arguments;
const now = Date.now();
if(now - prev >= delay){
func.apply(context, args);
prev = Date.now();
}
}
}
定时器版本
fucntion throttle(func, delay){
let timer = null;
return funtion(){
let context = this;
let args = arguments;
if(!timer){
timer = setTimeout(function(){
func.apply(context, args);
clearTimeout(timer);
timer = null;
}, delay);
}
}
}
防抖debounce
debounce 函数封装后,返回内部函数;每一次事件被触发,都会清除当前的 timer 然后重新设置超时并调用。这会导致每一次高频事件都会取消前一次的超时调用,导致事件处理程序不能被触发,只有当高频事件停止,最后一次事件触发的超时调用才能在 delay 时间后执行
高频触发的函数只到最后一次触发时执行
适用场景:
- search 搜索联想,用户在不断输入值时,用防抖来节约请求资源。
- window 触发 resize 的时候,不断的调整浏览器窗口大小
立即防抖
事件停止触发后才执行
function debounce(fun, delay) {
let timer = null;
return function() {
let context = this;
let args = arguments;
clearTimeout(timer);
timer = setTimeout(function() {
fn.apply(context, args);
}, delay);
};
}
非立即防抖
事件会立马触发一次,之后事件停止触发后再执行一次
function debouce(func,delay,immediate){
var timer = null;
return function(){
var context = this;
var args = arguments;
if(timer) clearTimeout(time);
if(immediate){
//根据距离上次触发操作的时间是否到达delay来决定是否要现在执行函数
var doNow = !timer;
//每一次都重新设置timer,就是要保证每一次执行的至少delay秒后才可以执行
timer = setTimeout(function(){
timer = null;
},delay);
//立即执行
if(doNow){
func.apply(context,args);
}
}else{
timer = setTimeout(function(){
func.apply(context,args);
},delay);
}
}
}
防抖和节流的结合
/**
* 函数节流方法
* @param Function fn 延时调用函数
* @param Number delay 延迟多长时间
* @param Number atleast 至少多长时间触发一次
* @return Function 延迟执行的方法
*/
var throttle = function (fn, delay, atleast) {
var timer = null;
var previous = null;
return function () {
var now = +new Date();
if ( !previous ) previous = now;
if ( atleast && now - previous > atleast ) {
fn();
// 重置上一次开始时间为本次结束时间
previous = now;
clearTimeout(timer);
} else {
clearTimeout(timer);
timer = setTimeout(function() {
fn();
previous = null;
}, delay);
}
}
};
case
// case 1
window.onscroll = throttle(testFn, 200);
// case 2
window.onscroll = throttle(testFn, 200, 500);
在上面的例子中,case1 没有传递 atleast 参数,那么 testFn 只会带 scroll 停止后才会执行,即为防抖
case2 有传递 atleast 参数,变现为第一次会延迟 500ms 执行,之后会每间隔 500ms 执行,即为节流
当然,上面的例子没有处理参数和 this 绑定问题,有待优化