在前端開發的過程當中常常會遇到這樣的需求--經過鼠標的事件(mousemove,srcoll 等)連續觸發目標函數,若是不與後臺交互,在某些狀況下還說的過去,可是一旦與後臺交互,好比Ajax請求,那麼這個時候會對後臺形成很大的壓力,那麼如何才能避免這種情況呢?這裏就不得不請出今天要說的主角--函數的防抖和節流。前端
函數節流: 不是讓函數不執行,而是讓函數在必定的時間內執行的次數減小一些服務器
函數防抖: 是超過必定的時間內執行一次,好比在mousemove
事件中,鼠標中止移動後的1s後才執行。 若是還不明白,能夠移步的這裏本身體驗一把吧,哈哈!函數防抖和節流體驗閉包
先看一個例子,效果圖(從參考文章上扒下來的,說明問題就好)app
var num = 1;
var content = document.querySelector('.container');
addNum ();
function addPlus() {
num++;
content.innerHTML = num
}
document.onmousemove = addNum
複製代碼
函數防抖前的樣子,能夠想象若是addPlus
裏面執行的不是簡單的計算,而是向服務器發送請求,能夠預見服務器要承擔多大的壓力。函數
若是使用防抖函數呢? 且看以下函數和效果圖post
document.onmousemove = debounce(addPlus,1000)
// 通常的防抖函數
function debounce(doSomething,wait){
var timeout;//須要一個外部變量,爲加強封裝,因此使用閉包
return function(){
var _this = this,
_arguments = arguments;
// 關鍵,每次執行前都要先清空上一個timeOut,因爲速度特別快,
// 因此在移動鼠標的時候,裏面的函數不會執行,直到當鼠標中止的時候,此時生成最後一個定時器
// 並1秒後調用doSomething
clearTimeout(timeout);
// 再生成一個Timeout
timeout = setTimeout(function(){
doSomething.apply(_this,_arguments);
},wait);
}
};
複製代碼
當即執行版ui
function debounceIm(doSomething,wait,isImmediate){
var timeout;
return function(){
var _this = this,
_arguments = arguments;
clearTimeout(timeout);
if(isImmediate){
var isTrigger = !timeout;
timeout = setTimeout(function(){
timeout = null;
}, wait)
isTrigger&&doSomething.apply(_this,_arguments);
}else{
timeout = setTimeout(function(){
doSomething.apply(_this,_arguments);
},wait);
}
}
}
document.onmousemove = debounceIm(addPlus,1000,true);
複製代碼
上述函數解析:this
若是isImmediate=true:
spa
當鼠標第一次開始移動的時候,timeout
是undefined
,因此isTrigger
是true
,因此就會當即執行isTrigger&&doSomething.apply(_this,_arguments)
;而且timeout
已是一個對象了,此時若是鼠標不停的移動就會致使isTrigger
是false
,延時器一直被清空,直到停下來的時候過wait
後執行timeout=null
。.net
若是isImmediate=false
:
就不說啦,跟第一次總結的同樣。
上述的效果圖以下:
截留的目的不是不執行,而是讓函數執行的頻率變低,一般有兩種方案,一種是使用時間戳,一種是使用定時器
時間戳版
function trottle(doSomeThing,wait) {
var _this,
_arguments,
initTime = 0;
return function(){
var now = +new Date();
_this = this;
_arguments = arguments;
// 當間隔時間大於必定的時間後才觸發對應的函數
if(now - initTime>wait){
doSomeThing.apply(_this,_arguments);
initTime = now;
}
}
}
document.onmousemove = trottle(addPlus,2000)
複製代碼
第一次mousemove
的時候,會當即執行一次(由於第一次mousemove
的時候now - initTime
很大),以後就看時間間隔了
定時器(主要思想是經過mousemove不停建立新的延時器)
function throttle(doSomething,wait){
var timeout;
return function(){
var _this = this;
_arguments = arguments;
if(!timeout){
timeout = setTimeout(function(){
// 主要是讓每次move的時候,使!timeout爲true
timeout = null;
doSomething.apply(_this,_arguments);
},wait);
};
}
}
document.onmousemove = throttle(addPlus,2000)
複製代碼
這個方法的執行過程是這樣的:
第一次mousemove
因爲timeout
是undefined
,因此會進入判斷並建立一個延時器,此時若是咱們當即不斷地mousemove
,!time
爲false
,就不會進入判斷,直到間隔wait
時間段後,timeout
爲null
,此後再mousemove
就會建立新的延時器,以此類推不斷地循環...
這篇文章主要記錄一下本身對參考文章的思考過程,其中可能會有疏漏,還望你們指正~