之前翻译了一篇博客,里面有讲到这个,今天单独拎出来聊聊。
前言
事件的触发权很多时候都属于用户,有些情况下会产生问题:
向后台发送数据,用户频繁触发,对服务器造成压力
一些浏览器事件:
window.onresize
、mousemove
等,触发的频率非常高,会造成浏览器性能问题
如果你碰到这些问题,那就需要用到这些技术了。
我们先来解释一下函数节流(Throttling)和函数防抖(Debouncing)的区别:
我们上班、生活每天都需要坐电梯,用这个比喻再恰当不过了:
函数防抖和我们平时坐电梯差不多,如果有人进电梯(用户触发事件),那将在10秒钟后出发(执行程序),这时如果又有人进电梯了(用户在10秒内再次触发事件),我们又得等10秒再出发(重新计时)。
函数节流就比较直观了,有人进电梯,就开始计时,每10秒运送一次,如果没有人,则待机。
这两种策略具体使用场景还得看你的实际需求了,但是,只要理解了这个思想,接下来的就好办了。
函数节流(Throttling)
函数节流的作用上面讲的很清晰了,接下来我们分析一下如何实现它:
var throttle = function(fn, interval) { //fn为要执行的函数,interval为延迟时间
var _self = fn, //保存需要被延迟执行的函数引用
timer, //定时器
firstTime = true; //是否第一次调用
return function() { //返回一个函数,形成闭包,持久化变量
var args = arguments, //缓存变量
_me = this;
if(firstTime) { //如果是第一次调用,不用延迟执行
_self.apply(_me, args);
return firstTime = false;
}
if(timer) { //如果定时器还在,说明上一次延迟执行还没有完成
return false;
}
timer = setTimeout(function() { //延迟一段时间执行
clearTimeout(timer);
timer = null;
_self.apply(_me, args);
}, interval || 500);
};
};
//使用
window.onresize = throttle(function() {
//你要执行的代码
}, 500);
其实函数节流和函数防抖的关键就是对setTimeout
的运用,说个题外话,当你对setTimeout
和setInterval
内部的运作原理彻底了解后,你就是一名JS大神了。😝
函数防抖(Debouncing)
我个人在开发中比较喜欢使用函数防抖策略,其实也说不上谁好,适应的场景不同。
我把注解也写在代码中了:
function debounce(fn, interval, immediate) {
//fn为要执行的函数
//interval为等待的时间
//immediate判断是否立即执行
var timeout; //定时器
return function() { //返回一个闭包
var context = this, args = arguments; //先把变量缓存
var later = function() { //把稍后要执行的代码封装起来
timeout = null; //成功调用后清除定时器
if(!immediate) fn.apply(context, args); //不立即执行时才可以调用
};
var callNow = immediate && !timeout; //判断是否立即调用,并且如果定时器存在,则不立即调用
clearTimeout(timeout); //不管什么情况,先清除定时器,这是最稳妥的
timeout = setTimeout(later, interval); //延迟执行
if(callNow) fn.apply(context, args); //如果是第一次触发,并且immediate为true,则立即执行
};
};
//使用
var myEfficientFn = debounce(function() {
//你要做的事
}, 250);
window.addEventListener('resize', myEfficientFn);
上面代码有一个巧妙的设计:var callNow = immediate && !timeout;
,判断了timeout,如果存在,说明有定时器在运行,那就不是第一次执行,则不执行if(callNow)
里的代码了。
总结
这两个代码块是在开发中经常使用的,无论是为了适应需求还是优化性能,我们都没有理由不适用它们。
另外在jQuery的源码中也使用了这种技巧,即便在这个框架横行的时代,还是只有底层的知识能让我感到踏实。
喜欢本文的朋友可以关注我的微信公众号,不定期推送一些好文。
本文出自Rockjins Blog,转载请与作者联系。否则将追究法律责任。