zoukankan      html  css  js  c++  java
  • throttle與debounce算法的邏輯

    throttledebounce,是兩個算法。兩者處理的對象,都是那些需要被反復調用的函數,特別是回調函數。其目的,都是控制函數重複執行的頻率,避免性能下降。
    throttle的應用場景如瀏覽器窗口的resize,debounce的應用場景如搜索框的suggestion。
    throttle的基本思想很簡單,通過封裝(包裹),使原函數相鄰兩次執行時間必須大於一個值interval。如果第二次調用函數的時機,沒有超出interval,則忽略之,或者用setTimeout使函數在超出interval的某個時機再執行原函數
    debounce的思路也很簡單,通過封裝(包裹),使函數第一次調用時,不馬上執行原函數,而是設置一個timeout。如果在timeout等待過程中,繼續調用這個函數,則取消現在的timeout,并重新設置一個。
    但是underscore庫中的這兩個函數,加了一些參數,使得邏輯非常複雜。即使每個函數的核心代碼就20行左右,我也要花兩三天時間才能理順。

    throttle

      _.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;
          //remaining > wait,在人為將系統時間調慢的情況下,成立
          if (remaining <= 0 || remaining > wait) {
            //由於setTimeout存在最小時間精度問題,因此有可能wait階段已過,但之前設置的setTimeout操作還未執行
            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;
        };
      };
    

    該函數的第三個參數options,有兩個屬性leadingtrailing,都是布爾值。他們能形成四種組合形式:

    1. {"trailing": true,"leading": true},是為默認值
    2. {"trailing": true,"leading": false}
    3. {"trailing": false,"leading": true}
    4. {"trailing": false,"leading": false}

    這個參數會影響程序的流程,現以流程圖分述之。
    下為{"trailing": true,"leading": true}的情況:
    true/true
    下為{"trailing": true,"leading": false}的情況:
    true/false
    下為{"trailing": false,"leading": true}的情況:
    false,true
    下為{"trailing": false,"leading": false}的情況:
    false,false
    leadingtrailing這兩個科技術語,一般是用來表示「首」和「尾」。但是通過上面流程圖的演示,可知在這段程序中,他們各自代表的意義,並非典型的前與後的對立關係。外國程序員在用詞方面的瑕疵,也給我們的閱讀造成了一定的困擾。

    debounce

    _.debounce = function(func, wait, immediate) {// immediate默認為false
        var timeout, args, context, timestamp, result;
        var later = function() {
            var last = _.now() - timestamp;//如果在wait期間,函數被調用,導致timestamp被更新,則原函數始終不會被執行,直到函數停止被調用
            if (last < wait && last >= 0) {//系統時間調慢之後,則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();//此處是重點,每次都更新timestamp,這個值會影響到後面later函數的執行
            var callNow = immediate && !timeout;
            if (!timeout) timeout = setTimeout(later, wait);
            if (callNow) {//第一次調用該函數,或者上一個timeout已經被執行完畢,且immediate為true,則立即執行func函數
                result = func.apply(context, args);
                context = args = null;
            }
            return result;
        };
    };
    

    immediate這個參數,目的在於,在不存在timeout的情況下,先同步執行一次原函數,然後再設置一個timeout
    以下是流程圖:
    debounce

    測試

    除了上面的源代碼,我也在自己的Javascript庫中實現了這兩個函數,沒有那麼多的參數,邏輯更加清楚。
    為了測試這兩個函數,我寫了一段簡單的代碼:

    var todo = function() {
        var now = new Date();
        console.log(now.getSeconds() + "," + now.getMilliseconds());
    };
    var callback = debounce(todo, 1230); //事件的響應函數,參數1230ms
    var interval = setInterval(function() {
        callback();
    }, 100); //事件每100ms觸發一次
    setTimeout(function() {
        clearTimeout(interval);
    }, 6 * 1000); //事件持續6s
    
  • 相关阅读:
    ionic localstorage
    angular 中文鏈接
    把jqmobi 變成jQuery 的插件 從此使用jQuery
    jqmobi 的一些設置
    ionic ngcordova map 地圖
    ionic pull to refresh 下拉更新頁面
    json 對象的序列化
    鍵盤彈出,頁面佈局被推上去了.....
    Cordova V3.0.0中config.xml配置文件的iOS Configuration
    android ios 只能輸入數字 不能輸入小數點的 函數 cordova
  • 原文地址:https://www.cnblogs.com/jonkee/p/5124335.html
Copyright © 2011-2022 走看看