Gzip自体:スクリプトを20%圧縮します

重複キー



Closure CompilerYUI Compressorなどで圧縮されたスクリプトを見ると、 .prototype



.length



offsetParent



の重複したキーの無限の文字列を見ることができます。 例としてjQuery UI Sortableプラグインを使用して、それらを取り除きましょう。 すぐにgzipを超えることはできないと言いますが、手元にない場合や使用できない場合(たとえば、 10K Apartのコンペティションなど)、この圧縮手法は非常に便利です。



jquery.ui.sortable.jsファイルバージョン1.8.2をjQuery UIバンドルで最も印象的なものの1つとしてみましょう。 ソースコードの重量は38.5 KBで、Closure Compilerで圧縮されています-23.1 KB、gzipで-5.71 KB。 画面を乱雑にしないために、いくつかの特徴的な方法を選択し、これが別個のプラグインである想像します_mouseCapture()



が好きだった:

  1. / *!
  2. *ソースコード
  3. * /
  4. 関数 ($){
  5. var
  6. _mouseCapture = functionevent 、overrideHandle){
  7. ifthis .reverting){
  8. falseを 返し ます
  9. }
  10. ifthis .options.disabled || this .options.type == 'static' )はfalseを 返し ます
  11. //最初にアイテムデータを更新する必要があります
  12. this ._refreshItems( event );
  13. //クリックされたノード(またはその親の1つ)がthis.itemsの実際のアイテムであるかどうかを調べる
  14. var currentItem = null 、self = this 、nodes = $( event .target).parents()。each( function (){
  15. if ($ .data( this' sortable -item' )== self){
  16. currentItem = $( this );
  17. falseを 返し ます
  18. }
  19. });
  20. if ($ .data( event .target、 ' sortable -item' )== self)currentItem = $( event .target);
  21. if (!currentItem) return false ;
  22. ifthis .options.handle && !! overrideHandle){
  23. var validHandle = false ;
  24. $( this .options.handle、currentItem).find( "*" ).andSelf()。each( function (){ ifthis == event .target)validHandle = true ;});
  25. if (!validHandle) return false ;
  26. }
  27. this .currentItem = currentItem;
  28. this ._removeCurrentsFromItems();
  29. trueを 返し ます
  30. };
  31. })(jQuery);




混乱しないように、それをテストプラグインと呼び、Sortable全体を元のプラグインと呼びます。 テストプラグインの重量は正確に1 KBで、圧縮形式で576バイト、gzipで391バイトです。



/*! <br> * <br> * , 576 <br> */ <br>( function (d){ var _mouseCapture= function (a,b){ if ( this .reverting) return false ; if ( this .options.disabled|| this .options.type== "static" ) return false ; this ._refreshItems(a); var c= null ,e= this ;d(a.target).parents().each( function (){ if (d.data( this , "sortable-item" )==e){c=d( this ); return false }}); if (d.data(a.target, "sortable-item" )==e)c=d(a.target); if (!c) return false ; if ( this .options.handle&&!b){ var f= false ;d( this .options.handle,c).find( "*" ).andSelf().each( function (){ if ( this ==a.target)f= true }); if (!f) return false } this .currentItem=c; this ._removeCurrentsFromItems(); return true }})(jQuery);







this



self





まず、 this



ユビキタスで非圧縮性の表現を取り除きます。 元のプラグインでは、587回以上使用されています(2.3 KBまたはコードの6%)。 関数の先頭にローカル変数self



を追加します。

var <br> self = this ;<br>





ここで、 this



関数の本体のすべてをself



に置き換えて、圧縮結果を確認します。

それは:

this .currentItem=e; this ._removeCurrentsFromItems();





次のようになりました:

d.currentItem=e;d._removeCurrentsFromItems();





テストプラグイン全体:

/*! <br> * this > self <br> * YUI Compressor, 552 <br> */ <br>( function (b){ var a= function (f,g){ var d= this ; if (d.reverting){ return false } if (d.options.disabled||d.options.type== "static" ){ return false }d._refreshItems(f); var e= null ,c=b(f.target).parents().each( function (){ if (b.data( this , "sortable-item" )==d){e=b( this ); return false }}); if (b.data(f.target, "sortable-item" )==d){e=b(f.target)} if (!e){ return false } if (d.options.handle&&!g){ var h= false ;b(d.options.handle,e).find( "*" ).andSelf().each( function (){ if ( this ==f.target){h= true }}); if (!h){ return false }}d.currentItem=e;d._removeCurrentsFromItems(); return true }})(jQuery);





悪くない! ところで、19行目のこのメソッドには、作成された関数にコンテキストを渡すためのself = this



宣言がすでにまったく同じでしたが、何らかの理由で最適化には使用されませんでした。 ここでは、このアナウンスメントを最初に示しただけで、追加できる別の関数では、少なくとも4文字が関数で使用されている場合(さらに70文字あります)、余分な数文字が返済されます。



キーと文字列



それでは、残りのコードを注意深く見てみましょう。 繰り返し式のoptions



target



data



"sortable-item"



などがはっきりと見えます。 それらのほとんどはオブジェクトまたは文字列のプロパティの名前であり、一部は元のプラグインで50〜60回検出されます。 コンプレッサーのうち、クロージャーコンパイラーのみがアドバンストモードでこれらの要素を圧縮(名前を短いものに変更)できますが、ここではほとんどすべてのプロパティをその場所で観察します。 最も可能性が高いのは、ライブラリをコンパイルする際に、外部の広範なリスト、非圧縮性の名前が与えられたことです。 最適化の方法は言語構文自体によって促されるため、この状況を修正したいという自然な欲求があります。 頻繁に使用されるキーをローカル変数にしましょう:

var <br> a = {<br> options: {<br> visible: true ,<br> mess: 'hi' <br> }<br> };







1:

if (a.options.visible) {<br> alert(a.options.mess);<br> a.options.visible = false ;<br>}



2:

var <br> o = 'options' ,<br> v = 'visible' ;<br> if (a[o][v]) {<br> alert(a[o].mess);<br> a[o][v] = false ;<br>}










2番目のオプションでは、 visible



を2回ではなく1回だけ書き込み、optionを3回ではなく1回書き込む必要がありました。 40キロバイトのプラグインの規模、さらにはアプリケーション全体の規模では、これによりコードサイズが明確に向上します(ただし、わかりやすさは向上しません)。



任意の言語で小さなスクリプトを記述して、コード内の式の頻度を決定し、それらを変数で自動的に置き換えることができます。 たとえば、次のような正規表現によって: /((\')|(\")|\.)\b([a-z_][\w-]+\w)\b(?(2)\')(?(3)\")/i



。 ソースプラグインの場合、175個の置換が取得されました。テストプラグインの場合は15個です。

  1. / *!
  2. *これを置き換える> self
  3. *キーと文字列の置き換え
  4. * /
  5. 関数 ($){
  6. var
  7. _reverting = ' reverting '// 3
  8. _options = 'options'// 51
  9. _disabled = 'disabled'// 4
  10. _type = 'type'// 2
  11. _static = 'static'// 2
  12. __refreshItems = '_refreshItems'// 2
  13. _target = 'target'// 4
  14. _parents = 'parents'// 2
  15. _each = 'each'// 5
  16. _data = 'data'// 5
  17. _sortable_item = ' sortable -item'// 6
  18. _handle = 'handle'// 2
  19. _find = 'find'// 2
  20. _currentItem = 'currentItem'// 52
  21. FALSE =!1、 // 30
  22. TRUE =!0、 // 11
  23. _mouseCapture = functionevent 、overrideHandle){
  24. var
  25. self = this ;
  26. if (self [_reverting]){
  27. FALSEを返します。
  28. }
  29. if (self [_options] [_ disabled] || self [_options] [_ type] == _static)FALSEを返します。
  30. self [__ refreshItems]( event );
  31. var currentItem = null 、nodes = $( event [_target])[_ parent]()[_ each]( function (){
  32. if ($ [_ data]( this 、_sortable_item)== self){
  33. currentItem = $( this );
  34. FALSEを返します。
  35. }
  36. });
  37. if ($ [_ data]( event [_target]、_sortable_item)== self)currentItem = $( event [_target]);
  38. if (!currentItem)はFALSEを返します。
  39. if (self [_options] [_ handle] &&!overrideHandle){
  40. var validHandle = FALSE;
  41. $(self [_options] [_ handle]、currentItem)[_ find]( "*" ).andSelf()[_ each]( function (){ ifthis == event [_target])validHandle = TRUE;});
  42. if (!validHandle)はFALSEを返します。
  43. }
  44. self [_currentItem] = currentItem;
  45. self._removeCurrentsFromItems();
  46. TRUEを返します。
  47. };
  48. })(jQuery);




変数の宣言は煩雑に見えますが、少なくとも元のプラグインのすべてのメソッドに共通することを忘れないでくださいが、理論的には、アプリケーション全体の名前の一般的な宣言を行うことができます。 「アクティビティのフィールド」が大きいほど、名前の圧縮はより効果的に機能します。 それらのそれぞれは、モジュールの先頭で1回だけ示され、その後はどこでも1文字または2文字の表現に置き換えられます。 圧縮された形式では、テストプラグインは見栄えがよくなります。

  1. / *!
  2. *これを置き換える> self
  3. *キーと文字列の置き換え
  4. * YUIコンプレッサー、395 B + JS美人
  5. * /
  6. 関数 (c){
  7. var b = function (v、w){
  8. var t = this ;
  9. if (t [e]){
  10. 戻る
  11. }
  12. if (t [m] [k] || t [m] [r] == f){
  13. 戻る
  14. }
  15. t [n](v);
  16. var u = null
  17. s = c(v [i])[g]()[q]( function (){
  18. if (c [l]( this 、j)== t){
  19. u = c( これ );
  20. 戻る
  21. }
  22. });
  23. if (c [l](v [i]、j)== t){
  24. u = c(v [i])
  25. }
  26. if (!u){
  27. 戻る
  28. }
  29. if (t [m] [d] &&!w){
  30. var x = o;
  31. c(t [m] [d]、u)[a]( "*" ).andSelf()[q]( function (){
  32. ifthis == v [i]){
  33. x = h
  34. }
  35. });
  36. if (!x){
  37. 戻る
  38. }
  39. }
  40. t [p] = u;
  41. t._removeCurrentsFromItems();
  42. hを返す
  43. }
  44. })(jQuery);




document



window



など。



これらのグローバルオブジェクトは、ローカル変数に割り当てられた場合も完全に圧縮されます。 テストプラグインでは、 document



window



使用されないため、一時的に隣接する_mouseDrag()



メソッドを使用します。

( function () {<br><br> if ( event .pageY - $( document ).scrollTop() < o.scrollSensitivity)<br> scrolled = $( document ).scrollTop($( document ).scrollTop() - o.scrollSpeed);<br> else if ($(window).height() - ( event .pageY - $( document ).scrollTop()) < o.scrollSensitivity)<br> scrolled = $( document ).scrollTop($( document ).scrollTop() + o.scrollSpeed);<br> <br> if ( event .pageX - $( document ).scrollLeft() < o.scrollSensitivity)<br> scrolled = $( document ).scrollLeft($( document ).scrollLeft() - o.scrollSpeed);<br> else if ($(window).width() - ( event .pageX - $( document ).scrollLeft()) < o.scrollSensitivity)<br> scrolled = $( document ).scrollLeft($( document ).scrollLeft() + o.scrollSpeed);<br><br>})();





このような画像は、スクリプトでよく見られます。 このようなコードは、ローカル変数がないため、スペースと不要な文字を削除することによってのみ圧縮されます。 次に、置換を使用した圧縮を見てみましょう。

( function () {<br> var g = document ,<br> f = window,<br> e = "scrollTop" ,<br> c = "scrollLeft" ,<br> b = "scrollSpeed" ,<br> d = "scrollSensitivity" ,<br> h = "pageY" ,<br> a = "pageX" ;<br><br> if ( event [h] - $(g)[e]() < o[d]) {<br> scrolled = $(g)[e]($(g)[e]() - o[b])<br> } else {<br> if ($(f).height() - ( event [h] - $(g)[e]()) < o[d]) {<br> scrolled = $(g)[e]($(g)[e]() + o[b])<br> }<br> }<br><br> if ( event [a] - $(g)[c]() < o[d]) {<br> scrolled = $(g)[c]($(g)[c]() - o[b])<br> } else {<br> if ($(f).width() - ( event [a] - $(g)[c]()) < o[d]) {<br> scrolled = $(g)[c]($(g)[c]() + o[b])<br> }<br> }<br><br>})();





これはオプティマイザーのABCですが、何らかの理由で、これらの単純なトリックは、適切な場所にある大規模なライブラリでもほとんど使用されません。 開発者がプロ​​ジェクトレベルでの速記変数の使用について一定の合意に達した場合、圧縮されたjQueryの重さは70 KBではなく、たとえば50になる可能性があります。



前の例では、jQueryラッパー内のドキュメントオブジェクトへの参照を使用して変数を作成することをお勧めします。

var <br> doc = document ,<br> $doc = $(doc);







叙情的な余談


jQueryで動的に作成された関数では、ほとんどの場合(はい)ラッパーに要素が必要であり、次のようにする必要があります。

$( 'li' ).each( function (index, item) {<br> var <br> $item = $(item)<br> /* do something with $item */ <br>});





このような構造は、ライブラリのソースにもあります。 そして、要素を持つjQueryオブジェクトが3番目のオプションパラメータにすぐに渡されるとしたら、どれほど簡単になるでしょう。

$( 'li' ).each( function (index, item, $item) {<br> /* do something with $item */ <br>});





美人!



結果



ただし、テストプラグインに戻ります。 最適化後、395バイトと576の重さが増え始め、31.4%を獲得しました。

/*! <br> * this > self <br> * <br> * YUI Compressor, 395 <br> */ <br>( function (c){ var b= function (v,w){ var t= this ; if (t[e]){ return o} if (t[m][k]||t[m][r]==f){ return o}t[n](v); var u= null ,s=c(v[i])[g]()[q]( function (){ if (c[l]( this ,j)==t){u=c( this ); return o}}); if (c[l](v[i],j)==t){u=c(v[i])} if (!u){ return o} if (t[m][d]&&!w){ var x=o;c(t[m][d],u)[a]( "*" ).andSelf()[q]( function (){ if ( this ==v[i]){x=h}}); if (!x){ return o}}t[p]=u;t._removeCurrentsFromItems(); return h}})(jQuery);







オリジナルのプラグインのスケールでは、変数宣言が追加されているため、当然ながら画像は多少異なります。 すべての操作の結果、圧縮された形式のプラグインの重量は正確に18 KBになり始め、ゲインは5.3 KB(21.5%)になりました。 しかし、逆にgzipは0.7 KB(13%)重いため、この手法は、何らかの理由でgzpが利用できない場合に最適です。 この方法で圧縮されたファイルは、gzipをサポートしていないSafari 2などの古いブラウザーにも提供できます。



ソースプラグインのサイズ(バイト単位):

ソースコード これ→自己 プロパティキャッシング
圧縮なし 39,495 40 241 41,148
YUI / CC 23,656 22 185 18 496
gzip 5 851 5,950 6 504


UPD:グローバルオブジェクトの圧縮の例を追加しました。



All Articles