防抖與節流(源碼學習)

防抖與節流(源碼學習)

最近本身擼了一個輪播圖,在點擊切換的時候,爲了尋求更好的用戶體驗,引入了節流,在此記錄對源碼的學習過程
源碼來源: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

相關文章
相關標籤/搜索