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