memoize-one源碼淺析

作用:同一個函數,在多次調用時,通過比較當前和上一次兩者的參數是否相等來減少函數的請求次數,從而提高性能;

memoize-one其核心主要使用閉包的工作原理,簡單的說就是將內部的函數存在內存中 ,那我們就由簡到難,通過舉一個簡單的例子來介紹memoize-one的使用場景,並逐步深入下去:

未使用memoize-one,called被打印了兩次:

const canThrow = (name) => {
  console.log('called');  // 執行了兩次
  return { name };
};
 
const value1 = canThrow('Alex');
const value2 = canThrow('Alex');

使用memoize-one,called只打印了一次:

const canThrow = (name) => {
  console.log('called');  // 執行了兩次
  return { name };
};
 
const memoized = memoizeOne(canThrow);
 
const value1 = canThrow('Alex');
const value2 = canThrow('Alex');

下面我們看一下memoize-one的源碼:

    (function (global, factory) {
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
  typeof define === 'function' && define.amd ? define(factory) :
  (global = global || self, global.memoizeOne = factory());
}(this, function () { 'use strict';
  
  // 淺比較兩次調用的參數
  function areInputsEqual(newInputs, lastInputs) {
      // 判斷兩者長度[入參的個數]是否相等,如果不等的話,則返回false, 就沒必要再繼續比較了
      if (newInputs.length !== lastInputs.length) {
          return false;
      }
      // 判斷兩次入參[一一對應]的值是否相等,如果有一個不相等,證明入參是不一樣的,返回false
      for (var i = 0; i < newInputs.length; i++) {
          if (newInputs[i] !== lastInputs[i]) {
              return false;
          }
      }
      return true;
  }

  function memoizeOne(resultFn, isEqual) {
      /**
       * @param {function} isEqual
       * isEqual可以是一些深比較的方法,比如lodash.isequal
      */
      // isEqual判斷isEqual是否有傳, 未傳使用 areInputsEqual
      if (isEqual === void 0) { isEqual = areInputsEqual; }
      var lastThis;
      var lastArgs = [];
      var lastResult;
      var calledOnce = false;
      function memoized() {
          var newArgs = [];
          // 將arguments遍歷複製給一個新的變量
          for (var _i = 0; _i < arguments.length; _i++) {
              newArgs[_i] = arguments[_i];
          }
          // 1. calledOnce、lastThis目的是判斷memoized方法是第二次(多次)被調用 2. isEqual(newArgs, lastArgs)判斷入參如果相等的話,就沒必要再去調用resultFn這個函數了
          if (calledOnce && lastThis === this && isEqual(newArgs, lastArgs)) {
              return lastResult;
          }
          // 將參數整合array, 再通過apply去調用函數
          lastResult = resultFn.apply(this, newArgs);
          calledOnce = true;
          lastThis = this;
          lastArgs = newArgs;
          return lastResult;
      }
      return memoized;
  }

  return memoizeOne;

}));

首先memoize-one接受兩個參數, 第一個參數是要執行的函數,第二個參數(非必填)可以是自定義比較值是否相等的一些方法;

1. 我們在通過memoizeOne(canThrow)調用時,其實返回的是一個未被執行的函數;

2. canThrow('Alex') 第一次被調用時,會通過resultFn.apply(this, newArgs) 得出lastResult的值返回出去;

3. canThrow('Alex') 第二次(多次)被調用時,

if (calledOnce && lastThis === this && isEqual(newArgs, lastArgs)) {
   return lastResult;
}

這個判斷條件會進行比較,如果條件成立,則證明當前和上一次的參數是一樣的,就會把上一次的結果返回出去,而不執行resultFn這個函數;

這樣我們就基本清楚了memoize-one的工作原理;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章