之前翻譯了一篇部落格,裡面有講到這個,今天單獨拎出來聊聊。
前言
事件的觸發權很多時候都屬於使用者,有些情況下會產生問題:
向後臺傳送資料,使用者頻繁觸發,對伺服器造成壓力
一些瀏覽器事件:
window.onresize
、mousemove
等,觸發的頻率非常高,會造成瀏覽器效能問題
如果你碰到這些問題,那就需要用到這些技術了。
我們先來解釋一下函式節流(Throttling)和函式防抖(Debouncing)的區別:
我們上班、生活每天都需要坐電梯,用這個比喻再恰當不過了:
函式防抖和我們平時坐電梯差不多,如果有人進電梯(使用者觸發事件),那將在10秒鐘後出發(執行程式),這時如果又有人進電梯了(使用者在10秒內再次觸發事件),我們又得等10秒再出發(重新計時)。
函式節流就比較直觀了,有人進電梯,就開始計時,每10秒運送一次,如果沒有人,則待機。
這兩種策略具體使用場景還得看你的實際需求了,但是,只要理解了這個思想,接下來的就好辦了。
函式節流(Throttling)
函式節流的作用上面講的很清晰了,接下來我們分析一下如何實現它:
var throttle = function(fn, interval) { //fn為要執行的函式,interval為延遲時間
var _self = fn, //儲存需要被延遲執行的函式引用
timer, //定時器
firstTime = true; //是否第一次呼叫
return function() { //返回一個函式,形成閉包,持久化變數
var args = arguments, //快取變數
_me = this;
if(firstTime) { //如果是第一次呼叫,不用延遲執行
_self.apply(_me, args);
return firstTime = false;
}
if(timer) { //如果定時器還在,說明上一次延遲執行還沒有完成
return false;
}
timer = setTimeout(function() { //延遲一段時間執行
clearTimeout(timer);
timer = null;
_self.apply(_me, args);
}, interval || 500);
};
};
//使用
window.onresize = throttle(function() {
//你要執行的程式碼
}, 500);複製程式碼
其實函式節流和函式防抖的關鍵就是對setTimeout
的運用,說個題外話,當你對setTimeout
和setInterval
內部的運作原理徹底瞭解後,你就是一名JS大神了。?
函式防抖(Debouncing)
我個人在開發中比較喜歡使用函式防抖策略,其實也說不上誰好,適應的場景不同。
我把註解也寫在程式碼中了:
function debounce(fn, interval, immediate) {
//fn為要執行的函式
//interval為等待的時間
//immediate判斷是否立即執行
var timeout; //定時器
return function() { //返回一個閉包
var context = this, args = arguments; //先把變數快取
var later = function() { //把稍後要執行的程式碼封裝起來
timeout = null; //成功呼叫後清除定時器
if(!immediate) fn.apply(context, args); //不立即執行時才可以呼叫
};
var callNow = immediate && !timeout; //判斷是否立即呼叫,並且如果定時器存在,則不立即呼叫
clearTimeout(timeout); //不管什麼情況,先清除定時器,這是最穩妥的
timeout = setTimeout(later, interval); //延遲執行
if(callNow) fn.apply(context, args); //如果是第一次觸發,並且immediate為true,則立即執行
};
};
//使用
var myEfficientFn = debounce(function() {
//你要做的事
}, 250);
window.addEventListener('resize', myEfficientFn);複製程式碼
上面程式碼有一個巧妙的設計:var callNow = immediate && !timeout;
,判斷了timeout,如果存在,說明有定時器在執行,那就不是第一次執行,則不執行if(callNow)
裡的程式碼了。
總結
這兩個程式碼塊是在開發中經常使用的,無論是為了適應需求還是優化效能,我們都沒有理由不適用它們。
另外在jQuery的原始碼中也使用了這種技巧,即便在這個框架橫行的時代,還是隻有底層的知識能讓我感到踏實。
喜歡本文的朋友可以關注我的微信公眾號,不定期推送一些好文。
本文出自Rockjins Blog,轉載請與作者聯絡。否則將追究法律責任。