背景
今天在coding的時候,做了一個搜尋框,也正是這個搜尋框,讓我和後臺小夥伴直接由鐵磁變為塑料兄弟。那到底發生啥了呢?其實很簡單,其實很無奈,就是我用王者的手速把他的介面訪問崩了!
我們在平時開發的時候,會有很多場景會頻繁觸發事件,比如說搜尋框實時發請求,onmousemove,resize,onscroll等等,有些時候,我們並不能或者不想頻繁觸發事件,咋辦呢?這時候就應該用到函式防抖和函式節流了!
函式防抖(debounce)
什麼是防抖?短時間內多次觸發同一個事件,只執行最後一次,或者只在開始時執行,中間不執行。舉個栗子:你去乘坐公交車,不停地上人,連續上人的過程中司機師傅是不會開車的,只有當最後一個人上車了,老司機才會開車!嘿嘿嘿!我們以不停地觸發onmousemove事件,讓數字+1為例。程式碼如下:
- 不使用防抖和節流,數字會像得了羊癲瘋一樣不停地增長
//變數初始化
var xcd = document.getElementById('xcd'),
count = 1;
//要執行的操作 數字+1
function doSomething() {
xcd.innerHTML = count++;
};
//觸發onmousemove事件 正常情況下
xcd.onmousemove = doSomething;
複製程式碼
- 使用防抖之綠色基礎版
//綠色基礎版:
function debounce(doSomething,wait){
var timeout;//需要一個外部變數,為增強封裝,所以使用閉包
return function(){
var _this = this,
_arguments = arguments;//arguments中存著e
clearTimeout(timeout);
timeout = setTimeout(function(){
doSomething.apply(_this,_arguments);
},wait);
}
}
//觸發onmousemove事件
xcd.onmousemove = debounce(doSomething,1000);
複製程式碼
這個綠色基礎版雖然簡單,但是已經能夠解決大部分需求場景了,沒有啥特殊需求使用這個版本就行了!用起來簡直像吃了巴豆一樣,duangduangduang,極其通暢!But,還會有一些其他需求,比如我想立即執行,就是連續觸發事件的開始時立即執行一次,後連續觸發不執行,我們用isImmediate表示是否立即執行,程式碼如下:
- 使用防抖之立即執行版
//立即執行版
function debounce(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);
}
}
}
//觸發onmousemove事件
xcd.onmousemove = debounce(doSomething,1000,true);
複製程式碼
函式節流(throttle)
什麼是節流?節流是連續觸發事件的過程中以一定時間間隔執行函式。節流會稀釋你的執行頻率,比如每間隔1秒鐘,只會執行一次函式,無論這1秒鐘內觸發了多少次事件。
舉個栗子:你每天要喝好多水,但是你不會每喝完一口水都要去一次廁所,如果有盆友是醬紫的話,我勸你還是去醫院看看吧→_→廁所看你都煩~你雖然一直在喝水,但是不會一直去廁所,通常的節奏是!喝水喝水喝水上廁所!喝水喝水喝水上廁所!雖然一直在觸發,但是每隔一段時間只會執行一次操作,這就是函式節流!
- 使用節流之時間戳版
//綠色基礎版之時間戳版
function throttle(doSomething,wait){
var _this,
_arguments,
initTime = 0;
return function(){
var now = +new Date();//將new date()轉化為時間戳
_this = this;
_arguments = arguments;
if(now - initTime>wait){
doSomething.apply(_this,_arguments);
initTime = now;
}
}
}
//觸發onmousemove事件
xcd.onmousemove = throttle(doSomething,1000);
複製程式碼
- 使用節流之定時器版
//綠色基礎版之定時器版
function throttle(doSomething,wait){
var timeout;
return function(){
var _this = this;
_arguments = arguments;
if(!timeout){
timeout = setTimeout(function(){
timeout = null;
doSomething.apply(_this,_arguments);
},wait);
};
}
}
//觸發onmousemove事件
xcd.onmousemove = throttle(doSomething,1000);
複製程式碼
同樣,以上兩個節流的綠色基礎版也可以滿足大多數需求場景啦!這兩個版本有什麼區別呢?時間戳版會在開始時立即執行一次,最後時間間隔內不再執行;定時器版開始時不執行,最後時間間隔內再執行一次。可以根據自己的實際需求選擇合適的版本。
當然,可能還有一些BT的產品會問你,能不能先立即執行一次,中間固定間隔時間執行,最後在執行一次呢?這就到了裝B的時候了。像我這麼牛X的前端,必須的啊,把兩種合在一起就行了,雙修什麼的最喜歡了*@ο@*
- 使用節流之雙劍合璧版
//節流之雙劍合璧版
function throttle(doSomething, wait) {
var timeout, _this, _arguments,
previous = 0;
var later = function() {
previous = +new Date();
timeout = null;
doSomething.apply(_this, _arguments)
};
var throttled = function() {
var now = +new Date();
//下次觸發 doSomething 剩餘的時間
var remaining = wait - (now - previous),
_this = this;
_arguments = arguments;
// 如果沒有剩餘的時間了
if (remaining <= 0) {
if (timeout) {
clearTimeout(timeout);
timeout = null;
}
previous = now;
doSomething.apply(_this, _arguments);
} else if (!timeout) {
timeout = setTimeout(later, remaining);
}
};
return throttled;
}
//觸發onmousemove事件
xcd.onmousemove = throttle(doSomething,1000);
複製程式碼
深入理解函式防抖和節流,合理選擇防抖或節流,能解決很多帕金森疾病,實乃出門旅行,居家生活之必備良品!OK就醬,我就是我,我瞅自己都上火!不定期分享一些前端知識點和麵試點,喜歡點波關注唄!
參考:https://github.com/mqyqingfeng/Blog