何为throttle, 何为debounce?javascript
谷歌翻译给出的意思:throttle 掐死??? debounce 去抖 css
好吧,按理解咱们习惯翻译成 ——节流。java
那么在什么场景下须要用到?jquery
场景一:onresize,onscroll,onmousemovegit
场景二:input,autocompletegithub
若是咱们什么都不作,浏览器将会频繁的调用你绑定的事件,若是电脑配置低就会感受卡滞,也就是你的应用性能太差。浏览器
入门级写法:——拖动就fire注册的事件app
function onResize(){
console.log('log');
};
window.addEventListener('resize',onResize,false)dom
进阶级写法:——等你安静了我再调用函数
var timer = null; function onResize(){ clearTimeout(timer); timer = setTimeout(function(){ console.log('log'); },200); }; window.addEventListener('resize',onResize,false)
这里有个问题:引入了变量timer,它其实属于onResize的,可是你不能放到onResie里面。这样写实在是太丑了,得想办法。
若是咱们把这个变量注册为onResize的属性,变成:
function onResize(){ clearTimeout(onResize.timer); //this is difference onResize.timer = setTimeout(function(){ console.log('log'); },200); }; window.addEventListener('resize',onResize,false)
插句:这种方法在proxy中用处比较大。你们都知道要移除注册给dom的事件,须要指向一致,这个proxy就能够派上用场了。i.e,仅仅是个栗子!
Contextmenu.prototype = { proxy: function(fn){ if(!fn._contextmenu_proxy){ fn._contextmenu_proxy = $.proxy(fn, this); } return fn._contextmenu_proxy; }, init:function(dialModel,dialView){ var me = this; $document.on('contextmenu',me.proxy(me.onContextMenu)); } }
再进阶级写法:——封装
网上漫天叫嚣着“面向对象,封装,继承……” 你要不封装一个,还面向过程 是否是会喷死?
上面咱们其实已经实现了基础的函数节流。但咱们不能每次都要写一样的逻辑吧。因此抽象一个公用函数来作这件事,具体能够这样实现。
jquery是这样作的,google 能搜到$.throttle,可是为啥我在源码里没搜到???
underscore.js是这样实现的:
_.throttle = function(func, wait, options) { var context, args, result; var timeout = null; var previous = 0; options || (options = {}); var later = function() { previous = options.leading === false ? 0 : new Date; timeout = null; result = func.apply(context, args); }; return function() { var now = new Date; if (!previous && options.leading === false) previous = now; var remaining = wait - (now - previous); context = this; args = arguments; if (remaining <= 0) { clearTimeout(timeout); timeout = null; previous = now; result = func.apply(context, args); } else if (!timeout && options.trailing !== false) { timeout = setTimeout(later, remaining); } return result; }; }; // Returns a function, that, as long as it continues to be invoked, will not
// be triggered. The function will be called after it stops being called for
// N milliseconds. If `immediate` is passed, trigger the function on the
// leading edge, instead of the trailing.
_.debounce = function(func, wait, immediate) { var timeout, args, context, timestamp, result; return function() { context = this; args = arguments; timestamp = new Date(); var later = function() { var last = (new Date()) - timestamp; if (last < wait) { timeout = setTimeout(later, wait - last); } else { timeout = null; if (!immediate) result = func.apply(context, args); } }; var callNow = immediate && !timeout; if (!timeout) { timeout = setTimeout(later, wait); } if (callNow) result = func.apply(context, args); return result; }; };
调用:
function updatePosition(){ //console.log('s');
};
//默认当即执行第一次,若是不想要当即执行,能够这样 _.throttle(updatePosition, 500,{leading:false});
//默认当你中止操做时会延时执行最后一次,若是不想要,能够这样 _.throttle(updatePosition, 500,{trailing:false});
var throttled = _.throttle(updatePosition, 500);
$(window).scroll(throttled);
//debonce——debonce的意思,打个比方:你乘电梯常常碰到快要关门时有人要上,电梯得再次开了让人上来。这个过程可能反复好几回,若是咱们一致等着,等到一个时间间隔没人时再关门,是否是方便很//多,不太形象,大概也能明白什么意思
function calculateLayout(){
console.log('resize');
};
//若是想要当即执行,传入参数true _.debounce(calculateLayout, 2000,true);
var lazyLayout = _.debounce(calculateLayout, 2000);
$(window).resize(lazyLayout);
baidu Tangram
貌似没看到??
好吧,咱们来实现一个简单的封装,不须要那么复杂,好理解的版本。
/* *author@http://wuya1234.github.io
*思路: 1.以前已经说过,能够用setTimeout延时处理太频繁的操做 2.可是咱们不想让操做过程一直没有反应,因此须要指定好比:每隔200毫秒无论怎样都执行一次 */
function throttle(fn,delay,mustRun){ var timer, t_start, previous; return function(){ var arg = arguments, scope = this; var now = +new Date; var defer = function(){ previous = now; fn.call(scope,arg); }; var diff = now - previous - delay; if(diff <= 0){ clearTimeout(timer); timeout = timer; previous = now; fn.call(scope,arg); }else{ timer = setTimeout(fn.call(scope,arg),diff); } }; }; function onResize(){ clearTimeout(onResize.timer); onResize.timer = setTimeout(function(){ console.log('log'); },200); }; window.addEventListener('resize',throttle(onResize),false);
更多相关知识能够到这些地方看看:
1.http://remysharp.com/2010/07/21/throttling-function-calls/