JavaScriptの最適化:スコープ、低レベルESとES5配列メソッド

今日は、次の操作を実行する2ブロックのコードをテストします。
配列を指定すると、次数2が5より大きいすべての要素を選択する必要があります。

青い角のオプションA:低レベルコード-古くて恐ろしい(部分的な最適化が可能)
  1. for ( i = 0 , res = [ ] ; i < c ; i ++ ) { t = a [ i ] ; if ( t >= 2.236067 ) { continue ; } else { res. push ( t * t ) ; } }
  2. for ( i = 0 , res = [ ] ; i < c ; i ++ ) { t = a [ i ] ; if ( t >= 2.236067 ) { continue ; } else { res. push ( t * t ) ; } }
  3. for ( i = 0 , res = [ ] ; i < c ; i ++ ) { t = a [ i ] ; if ( t >= 2.236067 ) { continue ; } else { res. push ( t * t ) ; } }
  4. for ( i = 0 , res = [ ] ; i < c ; i ++ ) { t = a [ i ] ; if ( t >= 2.236067 ) { continue ; } else { res. push ( t * t ) ; } }
  5. for ( i = 0 , res = [ ] ; i < c ; i ++ ) { t = a [ i ] ; if ( t >= 2.236067 ) { continue ; } else { res. push ( t * t ) ; } }
  6. for ( i = 0 , res = [ ] ; i < c ; i ++ ) { t = a [ i ] ; if ( t >= 2.236067 ) { continue ; } else { res. push ( t * t ) ; } }
  7. for ( i = 0 , res = [ ] ; i < c ; i ++ ) { t = a [ i ] ; if ( t >= 2.236067 ) { continue ; } else { res. push ( t * t ) ; } }
  8. for ( i = 0 , res = [ ] ; i < c ; i ++ ) { t = a [ i ] ; if ( t >= 2.236067 ) { continue ; } else { res. push ( t * t ) ; } }

赤いコーナーのオプションB:高レベルのコードは若くて美しい(部分的な最適化を受け入れられない)
  1. a。 map function t { return t * t } filter 関数 t { return t > 5 } ;

戦闘は3つのアリーナで行われます。
1. AO args-関数アクティブ化オブジェクトのパラメーター。
2. AO-関数アクティベーションオブジェクトのローカル変数。
3.グローバル-グローバル変数。



武器庫には、すべての一般的なブラウザの最新の安定バージョンがあります。

すべてのテストコード:
  1. // * * * * * * * * * * * * * * * * * *
  2. // Activationオブジェクトの引数スコープ
  3. // * * * * * * * * * * * * * * * * * *
  4. 関数 a dt index i c r t res {
  5. r = [ ] ;
  6. c = a。 長さ
  7. dt = 新しい日付 ;
  8. インデックス= 20000 ;
  9. while インデックス- {
  10. a。 map function t { return t * t } filter 関数 t { return t > 5 } ;
  11. }
  12. r [ 0 ] = 新しい日付 -dt ;
  13. dt = 新しい日付 ;
  14. インデックス= 20000 ;
  15. while インデックス- {
  16. for i = 0 res = [ ] ; i < c ; i ++ {
  17. t = a [ i ] ;
  18. if t > = 2.236067 {
  19. 続ける ;
  20. } else {
  21. 解像度 プッシュ t * t ;
  22. }
  23. }
  24. }
  25. r [ 1 ] = 新しい日付 -dt ;
  26. alert 'ao args:' + r ;
  27. } [ 1、2、3、4、5、6、7、8、9、10、1、2、3、4、5、6、7、8、9、10、1、2、3、4 5、6、7、8、9、10、1、2、3、4、5、6、7、8、9、10、1、2、3、4、5、6、7、8、9 10 ] )) ;
  28. // * * * * * * * * * * * * * * * * * *
  29. //アクティベーションオブジェクトのスコープ
  30. // * * * * * * * * * * * * * * * * * *
  31. 関数 {
  32. var a = [ 1、2、3、4、5、6、7、8、9、10、1、2、3、4、5、6、7、8、9、10、1、2、3 4、5、6、7、8、9、10、1、2、3、4、5、6、7、8、9、10、1、2、3、4、5、6、7、8 9、10 ]
  33. dt
  34. インデックス
  35. 私は
  36. c
  37. r
  38. t
  39. 解像度
  40. ;
  41. r = [ ] ;
  42. c = a。 長さ
  43. dt = 新しい日付 ;
  44. インデックス= 20000 ;
  45. while インデックス- {
  46. a。 map function t { return t * t } filter 関数 t { return t > 5 } ;
  47. }
  48. r [ 0 ] = 新しい日付 -dt ;
  49. dt = 新しい日付 ;
  50. インデックス= 20000 ;
  51. while インデックス- {
  52. for i = 0 res = [ ] ; i < c ; i ++ {
  53. t = a [ i ] ;
  54. if t > = 2.236067 {
  55. 続ける ;
  56. } else {
  57. 解像度 プッシュ t * t ;
  58. }
  59. }
  60. }
  61. r [ 1 ] = 新しい日付 -dt ;
  62. alert 'ao:' + r ;
  63. } ;
  64. // * * * * * * * * * * * * * * * * * *
  65. //グローバルスコープ
  66. // * * * * * * * * * * * * * * * * * *
  67. var a = [ 1、2、3、4、5、6、7、8、9、10、1、2、3、4、5、6、7、8、9、10、1、2、3 4、5、6、7、8、9、10、1、2、3、4、5、6、7、8、9、10、1、2、3、4、5、6、7、8 9、10 ]
  68. dt
  69. インデックス
  70. 私は
  71. c
  72. r
  73. t
  74. 解像度
  75. ;
  76. r = [ ] ;
  77. c = a。 長さ
  78. dt = 新しい日付 ;
  79. インデックス= 20000 ;
  80. while インデックス- {
  81. a。 map function t { return t * t } filter 関数 t { return t > 5 } ;
  82. }
  83. r [ 0 ] = 新しい日付 -dt ;
  84. dt = 新しい日付 ;
  85. インデックス= 20000 ;
  86. while インデックス- {
  87. for i = 0 res = [ ] ; i < c ; i ++ {
  88. t = a [ i ] ;
  89. if t > = 2.236067 {
  90. 続ける ;
  91. } else {
  92. 解像度 プッシュ t * t ;
  93. }
  94. }
  95. }
  96. r [ 1 ] = 新しい日付 -dt ;
  97. alert 'global:' + r ;


コード: pastebin.com/mqBdkXZG

結果


Ff高レベル低レベル
AO args45892
あお474122
グローバル479162
オペラ高レベル低レベル
AO args41622
あお42721
グローバル42849
クロム高レベル低レベル
AO args839
あお898
グローバル9828
高レベル低レベル
AO args15321
あお14624
グローバル14725
IE8高レベル低レベル
AO args脱落した441
あお脱落した393
グローバル脱落した822

まとめ


ご覧のとおり、トレンドはAO args | AOがGlobalよりも速いです。 これはECMAScript仕様から明らかです。アクティベーションオブジェクトの変数へのアクセスは、グローバルオブジェクトよりも「コードに近い」ため(AO)高速です。
ECMAScriptにはRubyのようなブロックがないため、配列の各要素に対して関数が呼び出され、関数の呼び出しはJSにとって高価な操作であるため、低レベルコードは高レベルコードよりも何倍も高速です。 高レベルのコードは最大20倍遅くなります!
ChromeはJITコンパイルを備えているため非常に高速ですが、頻繁に使用されるコードブロックについては(1回の実行で同じ結果が得られます)。
興味深い点は、Firefoxを示しています。AOargs(低)92; AO(低)122; AOは4分の1の速さで議論します。 これらの変数はすべてAO引数ですが、AOは同じオブジェクト内にありますが、AF AO引数では、結果から判断して、別のオブジェクトとして割り当てられます。

別の興味深いテスト。
  1. function r dt index i j {
  2. dt = 新しい日付 ;
  3. インデックス= 50000 ;
  4. while インデックス- {
  5. //ブロックA
  6. for i = 0 j = 0 ; i < 20 ; i ++ {
  7. j ++;
  8. }
  9. // -------
  10. }
  11. r [ 0 ] = 新しい日付-dt ;
  12. dt = 新しい日付 ;
  13. インデックス= 50000 ;
  14. while インデックス- {
  15. //ブロックB
  16. j 0 です。
  17. j ++; j ++; j ++; j ++; j ++;
  18. j ++; j ++; j ++; j ++; j ++;
  19. j ++; j ++; j ++; j ++; j ++;
  20. j ++; j ++; j ++; j ++; j ++;
  21. // -------
  22. }
  23. r [ 1 ] = 新しい日付-dt ;
  24. アラート r ;
  25. } [ ] ;


どのブロックが高速になりますか? 回答: pastebin.com/hXxQb6pk

UPD最終的には、すべてがインターフェイスの再描画(リフロー、リドロー)に依存しますが、私の実践が示しているように、リフローの最適化は十分ではありませんでした。 匿名関数の呼び出しによってかなりの部分が消費され、それらが削除され、特に古代のブラウザではかなりの増加が得られました。 この記事を行動の手引きとして受け取らないでください。あなたにとって便利だと思うコードを書いてください。 必要に応じて最適化することをお勧めします。

Source: https://habr.com/ru/post/J110391/


All Articles