lodashソースの分析は、重い-uniqメソッドです.

4477 ワード

lodash.jsバッグはnode開発でよく使われているjsツールバッグです.中には多くの実用的な方法があります.今日はよく使われている一つの方法を分析します.
使い方
    _.uniq([2, 1, 2])
    // => [2, 1]
ソースパッケージ
    // uniq.js
    import baseUniq from './.internal/baseUniq.js'
    
    function uniq(array) {
          return (array != null && array.length) ? baseUniq(array) : []
    }

    export default uniq
uniq関数はここでbaseUniqのパッケージを作っただけですので、引き続きbaseUniqのソースコードを見てください.
    // baseUniq.js
    import SetCache from './SetCache.js'
    import arrayIncludes from './arrayIncludes.js'
    import arrayIncludesWith from './arrayIncludesWith.js'
    import cacheHas from './cacheHas.js'
    import createSet from './createSet.js'
    import setToArray from './setToArray.js'
    
    const LARGE_ARRAY_SIZE = 200 //              
    function baseUniq(array, iteratee, comparator) {
      let index = -1
      let includes = arrayIncludes //     ,      while   
      let isCommon = true
    
      const { length } = array
      const result = []
      let seen = result
    
      if (comparator) {
        //    comparator,          
        isCommon = false
        includes = arrayIncludesWith // includes         arrayIncludesWith
      }
      else if (length >= LARGE_ARRAY_SIZE) { //     200   ,       
        //         ,     Set  (  Set           Set    )
        const set = iteratee ? null : createSet(array) 
        if (set) {
          return setToArray(set) //Set     (Set          ,      )    
        }
        isCommon = false //      
        includes = cacheHas // includes        hash  
        seen = new SetCache //    hash    
      }
      else {
        //          ,            ,            
        seen = iteratee ? [] : result
      }
      outer:
      while (++index < length) { //          
        let value = array[index] //        
        //                    ,        
        const computed = iteratee ? iteratee(value) : value 
        
        value = (comparator || value !== 0) ? value : 0
        if (isCommon && computed === computed) { //           
          let seenIndex = seen.length //                  
          while (seenIndex--) { //                
            if (seen[seenIndex] === computed) { //         
              continue outer //                outer:
            }
          }
          if (iteratee) { //         
            seen.push(computed) //         
          }
          result.push(value) //        
        }
         //           ,  includes  ,               
        else if (!includes(seen, computed, comparator)) {
          if (seen !== result) { //       ,result seen         
            seen.push(computed)
          }
          result.push(value) //        
        }
      }
      return result //     ,        
    }
    
    export default baseUniq
大体の流れ:
分析
1.下記のコードに注意してください.
    else if (length >= LARGE_ARRAY_SIZE) { //     200   ,       
    //         ,     Set  (  Set           Set    )
    const set = iteratee ? null : createSet(array) 
    if (set) {
      return setToArray(set) //Set     (Set          ,      )    
    }
  }
lodashは、現在の配列の長さを判断します.ES 6を呼び出す新しいSetデータタイプを配列した場合、Setタイプに重複する要素は存在しません.つまり、配列のデバックを行い、最後にset ToAray方法を呼び出して配列に戻り、Setタイプは反復可能なタイプであり、...拡張演算子を使用することができる.性能面では、jsは単一スレッドで実行されるため、大行列の循環がCPU時間を占有し、スレッドがブロックされる.Setタイプを使うと重い仕事を下の階に任せて処理し、性能を向上させます.だから、普段は重い需要がある時にSetタイプのデバックを考慮してもいいです.js実行層でサイクルをするのではなく、性能の最適化です.
2.次にSetを使って重いコードを処理するかどうかの戦略を見ます.
    outer:
      while (++index < length) { //          
        let value = array[index] //        
        
        value = (comparator || value !== 0) ? value : 0
        if (isCommon && computed === computed) { //           
          let seenIndex = seen.length //                  
          while (seenIndex--) { //                
            if (seen[seenIndex] === computed) { //         
              continue outer //                outer:
            }
          }
        }
      }
ここで2つのネストwhileを使って配列を巡回し、重複要素があるかどうかを判断することができます.このような論理は問題なく、通常の動作で最も一般的なデバックコード論理であり、コードの実行時間の複雑さはO(n^2)であり、実行時間は配列の増加に伴って指数レベルが増加するので、なぜlodashのuniq関数は最大の連接可能配列長を規定し、長さを超えてSetデ重量法を採用するのですか?性能の浪費を避ける

ES 6の出現は本当に大きくて便利なコードの編纂です.ES 6はこんなに便利です.なぜ私はこのような倉庫が好きですか?私の答えは効率的で優雅で安心です.作業時に成熟したライブラリを使用することはコードの品質を保証し、成熟したライブラリは一般的に性能部分を最適化します.