JavaScript函數節流
函數節流
函數節流就是節約函數的調用,讓函數少執行幾次,一般用在onmousemove,onresize這種我們只要稍微一動就會砰砰砰執行多次的事件處理函數上。如果處理函數很復雜有執行很多次就很耗性能關鍵了有的是沒有必要執行的。
我們先說一個經常遇見的情況,鼠標放在按鈕上顯示下拉菜單,鼠標離開下拉菜單消失,通常我們這么寫:
//title表示標題元素,content表示下拉菜單
$("#title").hover(function(){
$("#content").show();
},function(){
$("#content").hide();
})
當我們快速劃過的時候,會看到下拉菜單會先出現然后立即隱藏傳說中的閃一下,我們知道用戶快速劃過時一般情況下并不是要查看下拉菜單的,所以我們要避免下拉菜單閃一下的這種事,通常我們的做法就是加一個定時器:
var timer;
$("#title").hover(function(){
timer = setTimeout(function(){
$("#content").show();
},100)
},function(){
clearTimeout(timer);
$("#content").hide();
})
這樣當我們想查看菜單時只要把鼠標放在標題元素上下拉菜單就出現了,當我們鼠標快速劃過標題元素時并不會出現下拉菜單元素,避免了菜單閃一下的尷尬事。
繼續介紹函數節流。函數節流也是這個套路,假如我們想對onresize事件進行處理(假設handler是一個很復雜的處理函數):
$(window).resize(handler);
var a = 1;
function handler(){
console.log(a++);
}
我們在改變窗口大小的時候只要稍微動一下處理函數就會執行十幾次,這其實是完全沒必要的,如果處理函數有很多的DOM操作,這是很耗性能的,所以我們要盡可能的減少事件處理函數的執行次數。
我們也像上一個例子一樣使用一個定時器來實現:
$(window).resize(handler);
var a = 1;
var timer;
function handler(){
timer&&clearTimeout(timer);
timer = setTimeout(function(){
console.log(a++);
},50)
}
在我們改變瀏覽器大小的過程中事件處理函數并沒有執行,只有當停止時才會執行我們的處理函數。為了使用方便可以封裝成一個函數:
$(function(){
$(window).resize(function(e){
defer(this,200,handler)(e);
})
})
function handler(e){
console.log(e);
}
/**
**fn表示事件處理函數
**_this表示事件處理函數中的this指向
**delay表示延遲時間
*/
function defer(_this,delay,fn){
return function(){
fn.timer&&clearTimeout(fn.timer);
var arg = arguments;
fn.timer = setTimeout(function(){
fn.apply(_this,arg);
},delay)
}
}
這種方式在處理onresize事件上還算是實用的但是在onmousemove上就會感覺很尷尬了,對于onmousemove我們通常處理都是標識出一個物體的軌跡,如果用上面的方式那么在移動的過程中總是清除定時器導致處理函數不執行,當鼠標停止時處理函數才開始執行,就看到物體直接從起點跳到終點,過程無跡可尋!
為了記錄物體運動的軌跡我們需要在一定的間隔內就執行一次onmousemove的事件處理函數:
$(function(){
$("#demo").bind("mousedown",function(e){
var _this = this;
var left = $(this).offset().left;
var top = $(this).offset().top;
var downX = e.pageX;
var downY = e.pageY;
var disX = downX-left;
var disY = downY-top;
$(document).bind("mousemove",function(e){
defer(_this,200,handler)(e,disX,disY);
})
$(this).bind("mouseup",function(e){
handler.timer&&clearInterval(handler.timer);
$(document).unbind("mousemove");
$(this).unbind("mouseup");
})
})
})
function handler(e,disX,disY){
var currentX = e.pageX;
var currentY = e.pageY;
$(this).css({"top":currentY-disY+"px","left":currentX-disX+"px"});
console.log(1)
}
/**
**fn表示事件處理函數
**_this表示事件處理函數中的this指向
**delay表示延遲時間
**interval表示函數執行的間隔默認50ms
*/
function defer(_this,delay,fn,interval){
return function(){
fn.timer&&clearTimeout(fn.timer);
var arg = arguments;
var _interval = interval || 50;
fn.start?"":fn.start=+new Date();
var current = +new Date();
if(current-fn.start>=_interval){
fn.start = current;
fn.apply(_this,arg);
}else{
fn.timer = setTimeout(function(){
fn.apply(_this,arg);
},delay)
}
}
}
來自:http://www.cnblogs.com/shinhwazt/p/6021366.html