最近本身擼了一個輪播圖,在點擊切換的時候,爲了尋求更好的用戶體驗,引入了節流,在此記錄對源碼的學習過程
源碼來源:underscorehtml
函數防抖(debounce)
使用場景:如今咱們須要作一個搜索框,當用戶輸入文字,執行keyup事件的時候,須要發出異步請求去進行結果查詢。但若是用戶快速輸入了一連串字符,例如是5個字符,那麼此時會瞬間觸發5次請求,這確定不是咱們但願的結果。咱們想要的是用戶中止輸入的時候纔去觸發查詢的請求,這個時候函數防抖能夠幫到咱們
原理:讓函數在上次執行後,知足等待某個時間內再也不觸發次函數後再執行,若是觸發則等待時間從新計算git
function debounce (func, wait, immediate) { var timeout, result; var later = function (context, args) { timeout = null;//重置 if (args) result = func.apply(context, args); }; var debounced = restArguments(function (args) { if (timeout) clearTimeout(timeout);//若是觸發則等待時間從新計算 if (immediate) {//應用場景,好比提交表單,須要當即執行一次 var callNow = !timeout;//是否爲第一次觸發,若是是第一次觸發,timeout是undefined timeout = setTimeout(later, wait);//注意,這裏沒有args,僅僅只是在wait毫秒後重置清空timeout, if (callNow) result = func.apply(this, args);//若是是immediate且是第一次觸發,當即執行一次;result爲當即執行的結果,這裏this直接綁定到用戶的func } else { timeout = delay(later, wait, this, args);//settimeout,注意:這裏的this經過參數傳給later綁定到func } return result; }); //重置,取消執行 debounced.cancel = function () { clearTimeout(timeout); timeout = null; }; return debounced; };
函數節流(throttle)
使用場景:window.onscroll,以及window.onresize等,每間隔某個時間去執行某函數,避免函數的過多執行
原理:與函數防抖不一樣,它不是要在每完成某個等待時間後去執行某個函數,而是要每間隔某個時間去執行某個函數github
// leading:是否當即執行 // trailing: true // wait期間若是再次調用,是否會在週期後邊緣(wait剛結束)再次執行 //leading = true;trailing = true; 調用當即執行一次,wait期間若是再次調用,會在週期後邊緣(wait剛結束)再次執行 //leading = true;trailing = false; 調用當即執行一次,wait期間若是再次調用,什麼也不作 //leading = false;trailing = true; 調用需等待wait時間,wait期間若是再次調用,會在週期後邊緣(wait剛結束)執行 //leading = false;trailing = false; 調用需等待wait時間,wait期間若是再次調用,什麼也不作 function throttle (func, wait, options) { var timeout, context, args, result; var previous = 0;//上次執行時間 if (!options) options = {}; var later = function () { previous = options.leading === false ? 0 : _.now();//設置爲0的話下次調用會當即執行 timeout = null; result = func.apply(context, args);//可能設置timeout? if (!timeout) context = args = null; }; var throttled = function () { var now = _.now(); if (!previous && options.leading === false) previous = now;//若是不是當即執行 var remaining = wait - (now - previous);//剩餘時間 context = this; args = arguments; if (remaining <= 0 || remaining > wait) {//開始執行 if (timeout) { clearTimeout(timeout); timeout = null; } previous = now;//記錄執行時間 result = func.apply(context, args); if (!timeout) context = args = null; } else if (!timeout && options.trailing !== false) { timeout = setTimeout(later, remaining);//注意只有這個地方對timeout賦值了且調用了later } return result; }; //取消 throttled.cancel = function () { clearTimeout(timeout); previous = 0; timeout = context = args = null; }; return throttled; };
全部學習過程可見註釋,完整註釋GitHub地址
其中我在造輪播圖的輪子的過程當中,引入了節流來優化用戶主動點擊切換,一次來提高用戶體驗,感受上仍是好不少的。
輪播圖演示地址app