函數節流和函數防抖


這段時間去面試了兩家當前比較拽的互聯網公司,回來一總結,廣度略有,深度堪憂。這么看來可能覺得還是好事,最近沒事在掘金上看看,不知不覺的關注的標簽已經有40來個了。

eslint,requirejs,three,Web Components,函數式編程,Visual Studio Code,JSON,TypeScript,vuex,WebAssembly,HTTPS,WebGL,DOM,Canvas,敏捷開發,MVVM,React Native,響應式設計,HTTP,全棧,稀土,電子書,chrome,微信,代碼規范,CSS,正則表達式,Node.js, 前端框架, HTML,設計模式,面試,程序員,算法,架構,Webpack......

bla bla bla......

前端就是苦,前端就是累。代碼大家都能寫,寫出什么樣的代碼,那就是功力。

閑話說的太多了,前端時間自己用vue寫了個相當簡單的web音樂播放器,寫完畢以后一直有幾個問題困擾我。

1.vue如何高可用的組件開發。

2.自己寫的搜索(autoComplete),返回數據不准確,可能返回以前關鍵字查詢的結果。

3. vuex 如何在錯誤的時候不阻止程序的繼續執行。

 

這里我說的是第二個問題,

我原來的考慮,搜索的時候傳遞關鍵字過去, 返回的時候,除了被搜索到的數據,還包括關鍵字本身。

如果當前的輸入框的值和返回的數據的關鍵字匹配,那么展現,反之丟棄。

這里也有問題,如果關鍵字前后兩次相同,那就會數據填充兩次。比如關鍵字為  a->b->a,第一個a落后於b返回。但至少保證了展現的數據是自己期望的數據。

 

后來看了一下

百度的搜索,也是每次都發送請求,但是一些前面發送的請求會被取消掉,返回html和腳本

bing的搜索,也是每次都發送請求,沒有取消,返回數據,html和腳本。

搜狗,每次發送請求,沒有取消,返回的是數據+腳本。

但是都一個特點,就是返回的都足夠快,這就有點尷尬了。

 

回頭再看看自己搜索的問題,才發現問題的是自己的邏輯處理問題

1.當字符為空的時候沒有發請求但是沒有清空數據

2.oninput,focus處理有問題

 

暈死,一天在掘金看到函數節流和函數防抖,本事想應用到這個及時搜索上面來,可是啊哈,走歪了。

回歸,我們來說說函數節流和函數防抖。

 

函數節流 & 函數防抖

Throttling enforces a maximum number of times a function can be called over time. As in "execute this function at most once every 100 milliseconds".

Debouncing enforces that a function not be called again until a certain amount of time has passed without it being called. As in "execute this function only if 100 milliseconds have passed without it being called".

函數節流:是確保函數特定的時間內至多執行一次

函數防抖:是函數在特定的時間內不被再調用后執行

 

函數節流underscore的實現(解釋,借用的是JS魔法堂:函數節流(throttle)與函數去抖(debounce))

.throttle = function(func, wait, options) {
    /* options的默認值
     *  表示首次調用返回值方法時,會馬上調用func;否則僅會記錄當前時刻,當第二次調用的時間間隔超過wait時,才調用func。
     *  options.leading = true;
     * 表示當調用方法時,未到達wait指定的時間間隔,則啟動計時器延遲調用func函數,若后續在既未達到wait指定的時間間隔和func函數又未被調用的情況下調用返回值方法,則被調用請求將被丟棄。
     *  options.trailing = true; 
     * 注意:當options.trailing = false時,效果與上面的簡單實現效果相同
     */
    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;
      // 當到達wait指定的時間間隔,則調用func函數
      // 精彩之處:按理來說remaining <= 0已經足夠證明已經到達wait的時間間隔,但這里還考慮到假如客戶端修改了系統時間則馬上執行func函數。
      if (remaining <= 0 || remaining > wait) {
        // 由於setTimeout存在最小時間精度問題,因此會存在到達wait的時間間隔,但之前設置的setTimeout操作還沒被執行,因此為保險起見,這里先清理setTimeout操作
        if (timeout) {
          clearTimeout(timeout);
          timeout = null;
        }
        previous = now;
        result = func.apply(context, args);
        if (!timeout) context = args = null;
      } else if (!timeout && options.trailing !== false) {
        // options.trailing=true時,延時執行func函數
        timeout = setTimeout(later, remaining);
      }
      return result;
    };
  };

 

函數防抖在underscore的實現,其基本思路,就是內部計時,達到指定時間,就執行,不然啟用延時。

_.debounce = function(func, wait, immediate) {
    // immediate默認為false
    var timeout, args, context, timestamp, result;

    var later = function() {
      // 當wait指定的時間間隔期間多次調用_.debounce返回的函數,則會不斷更新timestamp的值,導致last < wait && last >= 0一直為true,從而不斷啟動新的計時器延時執行func
      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();
      // 第一次調用該方法時,且immediate為true,則調用func函數
      var callNow = immediate && !timeout;
      // 在wait指定的時間間隔內首次調用該方法,則啟動計時器定時調用func函數
      if (!timeout) timeout = setTimeout(later, wait);
      if (callNow) {
        result = func.apply(context, args);
        context = args = null;
      }

      return result;
    };
  };

 

那么應用場景:

函數節流(throttle

1. 頻繁的mousemove/keydown,比如高頻的鼠標移動,游戲射擊類的

2. 搜索聯想(keyup)

3. 進度條(我們可能不需要高頻的更新進度)

4. 拖拽的dragover等

5.  高頻的點擊,抽獎等(哈哈,邪惡)

 

函數防抖(debounce

 1. scroll/resize事件

 2. 文本連續輸入,ajax驗證/關鍵字搜索

參考:

函數節流去抖與函數柯里化

淺談 Underscore.js 中 _.throttle 和 _.debounce 的差異

JS魔法堂:函數節流(throttle)與函數去抖(debounce)

 The Difference Between Throttling and Debouncing

Javascript 函數節流和函數去抖場景介紹


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM