函數防抖與節流

underscore.js提供了不少頗有用的函數,今天想說說其中的兩個。這兩個函數都用於限制函數的執行。javascript

debounce

在解釋這個函數前,咱們先從一個例子看下這個函數的使用場景。假設咱們網站有個搜索框,用戶輸入文本咱們會自動聯想匹配出一些結果供用戶選擇。咱們可能首先想到的作法就是監聽keypress事件,而後異步去查詢結果。這個方法自己是沒錯的,可是若是用戶快速的輸入了一連串的字符,假設是10個字符,那麼就會在瞬間觸發了10次的請求,這無疑不是咱們想要的。咱們想要的是用戶中止輸入的時候纔去觸發查詢的請求,這時候函數防抖能夠幫到咱們。java

函數防抖就是讓某個函數在上一次執行後,知足等待某個時間內再也不觸發此函數後再執行,而在這個等待時間內再次觸發此函數,等待時間會從新計算。瀏覽器

咱們先看下underscore.js裏相關函數的定義:app

_.debounce(function, wait, [immediate])異步

javascript// Returns a function, that, as long as it continues to be invoked, will not
// be triggered. The function will be called after it stops being called for
// N milliseconds. If `immediate` is passed, trigger the function on the
// leading edge, instead of the trailing.
_.debounce = function(func, wait, immediate) {
  var timeout, args, context, timestamp, result;

  var later = function() {
    var last = _.now() - timestamp;

    if (last < wait && last >= 0) {
      timeout = setTimeout(later, wait - last);
    } else {
      timeout = null;
      if (!immediate) {
        result = func.apply(context, args);
        if (!timeout) context = args = null;
      }
    }
  };

  return function() {
    context = this;
    args = arguments;
    timestamp = _.now();
    var callNow = immediate && !timeout;
    if (!timeout) timeout = setTimeout(later, wait);
    if (callNow) {
      result = func.apply(context, args);
      context = args = null;
    }

    return result;
  };
};

參數function是須要進行函數防抖的函數;參數wait則是須要等待的時間,單位爲毫秒;immediate參數若是爲true,則debounce函數會在調用時馬上執行一次function,而不須要等到wait這個時間後,例如防止點擊提交按鈕時的屢次點擊就可使用這個參數。函數

因此,上面那個場景,咱們能夠這麼解決:佈局

javascriptfunction query() { 
  //進行異步調用查詢 
}

var lazyQuery = _.debounce(query, 300);
$('#search').keypress(lazyQuery);

throttle

咱們網站常常會有這樣的需求,就是滾動瀏覽器滾動條的時候,更新頁面上的某些佈局內容或者去調用後臺的某接口查詢內容。一樣的,若是不對函數調用的頻率加以限制的話,那麼可能咱們滾動一次滾動條就會產生N次的調用了。可是此次的狀況跟上面的有所不一樣,咱們不是要在每完成等待某個時間後去執行某函數,而是要每間隔某個時間去執行某函數,避免函數的過多執行,這個方式就叫函數節流網站

一樣的,咱們看下underscore.js裏相關函數的定義:this

_.throttle(function, wait, [options])code

javascript// Returns a function, that, when invoked, will only be triggered at most once
// during a given window of time. Normally, the throttled function will run
// as much as it can, without ever going more than once per `wait` duration;
// but if you'd like to disable the execution on the leading edge, pass
// `{leading: false}`. To disable execution on the trailing edge, ditto.
_.throttle = function(func, wait, options) {
  var context, args, result;
  var timeout = null;
  var previous = 0;
  if (!options) options = {};
  var later = function() {
    previous = options.leading === false ? 0 : _.now();
    timeout = null;
    result = func.apply(context, args);
    if (!timeout) context = args = null;
  };
  return 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);
    }
    return result;
  };
};

參數function是須要進行函數節流的函數;參數wait則是函數執行的時間間隔,單位是毫秒。option有兩個選項,throttle第一次調用時默認會馬上執行一次function,若是傳入{leading: false},則第一次調用時不執行function。{trailing: false}參數則表示禁止最後那一次延遲的調用。具體能夠看源碼進行理解。

因此,在滾動滾動條的場景,咱們能夠這麼作:

javascriptfunction handleScroll() { 
  //進行滾動時的相關處理 
}

var throttled = _.throttle(handleScroll, 100);
$(window).scroll(throttled);

參考

http://underscorejs.org/#debounce
http://underscorejs.org/#throttle

相關文章
相關標籤/搜索