函数节流和防抖在前端开发中应用广泛,例如:函数防抖可以用于对用户输入的自动补全操作、函数节流可以用于对用户浏览行为的捕捉。
防抖
函数在事件触发 n 秒后才执行,如果一个事件触发的 n 秒内又触发了这个事件,那就以新的事件的触发时间为准
基本版
function denounce(func, wait) {
var timeout;
return function (){
clearTimeout(timeout);
setTimeout(func, wait);
}
}
解决 setTimeout 执行过程中 this 指向问题
function debounce (func, wait){
var timeout
return function (){
var that = this
clearTimeout(timeout)
timeout = setTimeout(function(){
func.apply(that)
}, wait)
}
}
解决 event 参数传递
function debounce (func, wait){
var timeout
return function (){
var args = arguments
var that = this
clearTimeout(timeout)
timeout = setTimeout(function(){
func.apply(that, args)
}, wait)
}
}
加上可立即执行判断
function debounce (func, wait, immediate){
var timeout
return function (){
var args = arguments
var that = this
clearTimeout(timeout)
if (immediate){
if (!timeout){
func.apply(that, args)
}
timeout = setTimeout(function(){
timeout = null
}, wait)
} else {
timeout = setTimeout(function(){
func.apply(that, args)
}, wait)
}
}
}
加上返回值
function debounce (func, wait, immediate){
var timeout, result
return function (){
var args = arguments
var that = this
clearTimeout(timeout)
if (immediate){
if (timeout){
result = func.apply(that, args)
}
timeout = setTimeout(function(){
timeout = null
}, wait)
} else {
timeout = setTimeout(function(){
func.apply(that, args)
}, wait)
}
return result
}
}
增加取消上次防抖等待
function debounce (func, wait, immediate){
var timeout, result
var debounced = function (){
var args = arguments
var that = this
clearTimeout(timeout)
if (immediate){
if (!timeout){
result = func.apply(that, args)
}
timeout = setTimeout(function(){
timeout = null
}, wait)
} else {
timeout = setTimeout(function(){
func.apply(that, args)
}, wait)
}
return result
}
debounced.cancel = function(){
clearTimeout(timeout)
timeout = null
}
return debounced
}
节流
函数在每个规定时间间隔内只会被触发一次
两种基本方式
时间戳版(效果:第一次触发马上执行,最后一次触发不会有效果)
function throttle(func, wait) {
var pre = 0
return function(){
var now = Date.now()
var that = this
var args = arguments
if (now - pre > wait) {
func.apply(that, args)
pre = now
}
}
}
定时器版(效果:第一次触发延迟执行,最后一次触发有效果)
function throttle(func, wait){
var timeout
return function(){
var that = this
var args = arguments
if (!timeout) {
timeout = setTimeout(function (){
timeout = null;
func.apply(that, args)
}, wait)
}
}
}
结合可配置版
function throttle(func, wait, options) {
var timeout, context, args, result;
var previous = 0;
if (!options) options = {};
var later = function() {
previous = options.leading === false ? 0 : new Date().getTime();
timeout = null;
func.apply(context, args);
if (!timeout) context = args = null;
};
var throttled = function() {
var now = new Date().getTime();
if (!previous && options.leading === false) previous = now;
var remaining = wait - (now - previous);
context = this;
args = arguments;
if (remaining <= 0 || remaining > wait) {
if (timeout) {
clearTimeout(timeout);
timeout = null;
}
previous = now;
func.apply(context, args);
if (!timeout) context = args = null;
} else if (!timeout && options.trailing !== false) {
timeout = setTimeout(later, remaining);
}
};
return throttled;
}