Reselect源碼解析

Reselect源碼解析

原文:Reselect源碼解析javascript

Reselect主要爲Redux的state數據提供了Memoize功能。它可以計算數據,傳遞最少且必要的state值;具備高性能,只在傳遞值改變時纔會從新計算;具備可組合性,能夠將它做爲參數傳遞給其餘selectors執行。html

下面是個最基礎的使用方式,能夠跳轉codepen來運行栗子java

基礎用法

createSelector

createSelector方法是Reselect的核心方法,最後一個參數默認爲回調函數,其餘參數能夠爲state、selector或數組,其中回調函數會引用其餘參數做爲本身的參數調用。數組

createSelector實際上調用的是Reselect中叫作createSelectorCreator的API,該API容許咱們開發定製版本的createSelectorapp

createSelectorCreator被調用時會引用默認的Memoize方法來校驗輸入數據,在源碼中叫作defaultMemoize,該方法返回的函數就是用來判斷是直接返回已經記憶的計算結果仍是從新計算並返回新的結果。函數

// func就是createSelector參數中最後一個函數參數
// equalityCheck參數默認獲取defaultEqualityCheck方法
// defaultEqualityCheck代碼就是判斷是否全等的函數:(a, b) => a === b
export function defaultMemoize(func, equalityCheck = defaultEqualityCheck) {
  let lastArgs = null
  let lastResult = null
  return function () {
    // 比較舊的和新的state是否全等
    // 若是不相等,則從新計算並將結果賦值給lastResult
    if (!areArgumentsShallowlyEqual(equalityCheck, lastArgs, arguments)) {
      lastResult = func.apply(null, arguments)
    }

    lastArgs = arguments
    return lastResult
  }
}
複製代碼

上面代碼中的areArgumentsShallowlyEqual方法思路很簡潔,使用for循環依次比較傳入的兩個數組中的每個值是否全等。性能

咱們接下來看一下createSelectorCreator的代碼是如何使用defaultMemoize的。優化

// memoize默認爲上面介紹的defaultMemoize
// memoizeOptions做爲memoize方法的引用參數
// 若是沒有傳值則默認爲equalityCheck = defaultEqualityCheck
export function createSelectorCreator(memoize, ...memoizeOptions) {
  return (...funcs) => {
    // 統計計算次數
    let recomputations = 0
    // 獲取selector參數中的最後一個回調函數
    const resultFunc = funcs.pop()
    // getDependencies函數獲取其他的參數 先判斷第一個參數是否爲數組
    // 若是是則返回第一個數組 不然直接返回
    // 注意:參數中具體的項必須爲函數類型,不然會拋出一個錯誤
    const dependencies = getDependencies(funcs)
    // 根據傳入的arguments來判斷是否從新計算結果
    const memoizedResultFunc = memoize(
      function () {
        recomputations++
        
        return resultFunc.apply(null, arguments)
      },
      ...memoizeOptions
    )

    // 根據傳入的state是否改變來判斷需不須要執行下面代碼
    const selector = memoize(function () {
      const params = []
      const length = dependencies.length

      for (let i = 0; i < length; i++) {
        params.push(dependencies[i].apply(null, arguments))
      }

      return memoizedResultFunc.apply(null, params)
    })

    selector.resultFunc = resultFunc
    selector.dependencies = dependencies
    selector.recomputations = () => recomputations
    selector.resetRecomputations = () => recomputations = 0
    return selector
  }
}
複製代碼

總結

Reselect的源碼很精簡,閱讀後可以提高對於Memoization和React優化的理解。做者在註釋中屢次說明使用for代替forEachevery,使用arguments而不是展開運算符是爲了更快和提升性能。Reselect的官方文檔閱讀起來也很是的清晰和輕鬆,對於常見問題的解答也是很全面,這點要點贊。ui

相關文章
相關標籤/搜索