1. 程式人生 > >簡單的去抖(debounce)處理 和 節流(throttle) 附 原始碼

簡單的去抖(debounce)處理 和 節流(throttle) 附 原始碼

為什麼需要消抖、節流?

原因:事件頻繁觸發,頻繁的操作DOM,或者頻繁的向伺服器請求資料,嚴重消耗效能 或導致頁面崩潰

  • window物件的resizescroll事件
  • 拖拽時的mousemove事件
  • 射擊遊戲中的mousedownkeydown事件
  • 文字輸入、自動完成的keyup事件

簡單debounce的例子:

<template>
  <div>
    <input type="number" v-model="num">
  </div>
</template>

<script>
import { debounce } from '@/utils'
export default {
  data () {
    return {
      num: ''

    }
  },
  watch: {
    // 如果不加debounce節流,會在num變化之後,立即執行
    // num () {
    //   console.log(this.num)
    // }
    // 加上debounce之後,num變化,會在1s之後,執行此函式
    num: debounce(function () {
      console.log(this.num)
    }, 1000)

  }

}
</script>

debounce.js (引用 underscore.js)

function(func, wait, immediate) {
  var timeout, result;
  var later = function(context, args) {
    timeout = null;
    if (args) result = func.apply(context, args);
  };
  var debounced = restArgs(function(args) {
    var callNow = immediate && !timeout;
    if (timeout) clearTimeout(timeout);
    if (callNow) {
      //如果立即呼叫,就設定一個定時,並且呼叫下方法。
      timeout = setTimeout(later, wait);
      result = func.apply(this, args);
    } else if (!immediate) {
      //否則,更新定時的時間
      timeout = _.delay(later, wait, this, args);
    }
    return result;
  });
  debounced.cancel = function() {
    clearTimeout(timeout);
    timeout = null;
  };
  return debounced;
};
throttle.js  節流原始碼 (引用 underscore.js)
function(func, wait, options) {
    var timeout, context, args, result;
    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;
    };

    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);
      }
      return result;
    };

    throttled.cancel = function() {
      clearTimeout(timeout);
      previous = 0;
      timeout = context = args = null;
    };

    return throttled;
  };