原文地址: https://www.jeremyjone.com/704/,轉載請註明。
什麼是防抖
事件響應函數在一段時間後才執行,如果在這段時間內再次調用,則重新計算執行時間;當預定的時間內沒有再次調用該函數,則執行該函數。
防抖做什麼
防止某些函數的頻繁調用,保證頁面的穩定流暢和數據準確性。
一個小的例子
使用 underscore 的防抖功能來測試一下效果。
在頁面中直接導入cdn即可。
https://cdn.bootcss.com/underscore.js/1.9.1/underscore.js
未防抖時的樣子
將下面內容粘貼到一個HTML的body標籤中。
<div id="container" style="width:100%;height:200px;line-height:200px;text-align:center;color:#fff;background-color:#444;font-size:30px;"></div>
<script>
let count = 0;
let container = document.querySelector("#container");
// 此處爲高頻調用函數
function doSomething() {
container.innerHTML = count++;
}
container.onmousemove = doSomething;
</script>
這段代碼會生成一個灰色框,只要鼠標在其內部移動,就會調用 doSomething
函數,導致數字不斷增長。
使用防抖
同樣地,將下面內容粘貼到一個新的HTML的body標籤中。
<div id="container" style="width:100%;height:200px;line-height:200px;text-align:center;color:#fff;background-color:#444;font-size:30px;"></div>
<script src="https://cdn.bootcss.com/underscore.js/1.9.1/underscore.js"></script>
<script>
let count = 0;
let container = document.querySelector("#container");
// 此處爲高頻調用函數
function doSomething() {
container.innerHTML = count++;
}
container.onmousemove = _.debounce(doSomething, 300);
</script>
這裏導入了
underscore
庫,這個庫會導出一個_
的對象,它包含一個debounce
方法,該方法的作用就是防抖。第一個參數是函數原型,第二個參數是響應時間,另外還可以設置是否立即執行,如果是,傳入true
。這裏我們設置300ms後響應。
這次運行後,可以發現當鼠標移動時,不再一味地增加,而是當鼠標靜止或移出後一段時間(300ms)纔會響應。
手動實現防抖函數
如果僅僅使用防抖函數,導入一個庫是得不償失的,因爲防抖函數本身並不大,所以可以手寫一個。
function debounce(func, wait, immediate) {
let timeout, result;
var debounced = function() {
// 獲取上下文,關聯this的指向
let context = this;
// 獲取所有參數
const args = arguments;
// 每次防抖都清除定時器,然後設置一個新的定時器。
if (timeout) clearTimeout(timeout);
// 區別是否立即執行
if (immediate) {
// 如果立即執行,需要一個變量控制重複執行。這裏利用timeout取反,可以控制效果
let callNow = !timeout;
timeout = setTimeout(() => {
timeout = null;
}, wait);
// 立即執行
if (callNow) result = func.apply(context, args);
} else {
// 不立即執行,則正常定時器等待即可
timeout = setTimeout(function() {
result = func.apply(context, args);
}, wait);
}
// 返回調用函數的結果
return result;
}
// 設置一個清除函數,可以手動控制取消防抖函數的執行。
debounced.cancel = function() {
clearTimeout(timeout);
timeout = null;
}
return debounced;
}