沒有防抖:
var count = 1;
var container = document.getElementById('container');
function getUserAction() {
container.innerHTML = count++;
};
container.onmousemove = getUserAction;
此時,鼠標移動,getUserAction方法就會頻繁的被觸發。醬紫可不好,浪費資源是吧。
防抖優化的第一版代碼
// 第一版
function debounce(func, wait) {
var timeout;
return function () {
clearTimeout(timeout)
timeout = setTimeout(func, wait);
}
}
// 這裏用了高階函數trick,還用了閉包
container.onmousemove = debounce(getUserAction, 1000);
函數解析:
函數內部,保存了timeout這個延遲函數(定時器),然後返回了一個匿名函數作爲container.onmousemove的響應函數。
當用戶有鼠標移動的動作的時候,首先清理定時器,然後,新建一個定時器,在wait時間後,才執行getUserAction。
這樣,如果在wait時間內,鼠標移動函數又一次被觸發,上一個定時器就被清理,然後重新建立一個新的定時器,在wait時間後執行getUserAction。
這樣的結果就是,只有在wait時間內,鼠標動作沒有被再次觸發,函數getUserAction纔會被執行。
this和event
使用了debounce函數,可能會導致this丟失,我們需要修改一下代碼:
// 第二版
function debounce(func, wait) {
var timeout;
return function () {
var context = this; // 作爲事件的直接響應函數,此時,this依舊指向document.getElementById('container')元素
clearTimeout(timeout)
timeout = setTimeout(function(){
func.apply(context) // apply函數可以修改函數this的指向
}, wait);
}
}
下面,我們想辦法把event也傳進去
event會作爲debounce函數返回的匿名函數的參數。
// 第三版
function debounce(func, wait) {
var timeout;
return function () {
var context = this;
var args = arguments;
clearTimeout(timeout)
timeout = setTimeout(function(){
func.apply(context, args)
}, wait);
}
}
於是我們修復了兩個問題:this指向,event對象。