標籤:show timer 效能 app html defer java return sed
函數節流
技術一般水平有限,有什麼錯的地方,望大家指正。
函數節流就是節約函數的調用,讓函數少執行幾次,一般用在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) } }}
查看效果。基本使用就是這些更多知識可以在網上查詢。
JavaScript函數節流