作用:同一個函數,在多次調用時,通過比較當前和上一次兩者的參數是否相等來減少函數的請求次數,從而提高性能;
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的工作原理;