DoT.jsテンプレートエンジンの改善

テンプレート動物園の時代は過ぎ、今ではMVC恐竜が走り回っており、組み込みのテンプレートエンジンとコンポーネントビルダーを使用しています。 しかし、KnockoutとBackboneの古いあまり便利ではないテンプレートエンジンを置き換えるには、時々必要になります。基本的に、2014年頃のレベルで開発を停止しました。



これはDoT.jsで発生しました。 2013年に約1年間執筆者に最初に見捨てられた彼は、バージョン1.0.1から1.1.1に上昇し、一時的に注目を集め、再び見捨てられました(または、理由に応じて安定しました)。 この点で、2013年には( DoT.jsのクローンを作成するために )必要でしたが、今ではそれアップグレードする必要がありました。



Underscore / Lodashの_.template()



と同じくらい高速ですが、テンプレートにJSを記述する必要性が一般的ではない構文が改善されていますが、Underscorでは常に必要です。 彼らは、スクリプト付きのこれらの括弧の特別な用語であるjavascript encapulated section(JES)を思いつき、基本的にそれらを取り除きました。



さらに何が得られますか?



1.テンプレートエンジンの構造が再設計され(2013年、そこからのリンク) 、読みやすくなり、デコード機能の数が減りました。

2. テストでは 、平均速度が変化していないことが示されています(パラメーターによって変動-3%-+ 10%)。

3.アレイの作業と同様に、構造の作業チームが追加されました。

4. 4番目のパラメーター-構造体または配列の要素のフィルター。

5.一部の場所では、バイパスバグによるスローダウンは、コードと正規表現の最適化によって補償されます。

6.グローバル名「doT」は、設定で別の名前に変更できます(元の-いいえ)。

7.グローバル関数のバージョン番号付けとバージョン付けの順序encodeHTML()-最適化のためにここで採用されたインスタンスが配置されました。



バージョン番号の参照用



npmでは、package.jsonの1対1のバージョン1.1.1のコピーの名前は1.1.2ですが、ファイル内では-番号1.1.1が残ります。 リポジトリ2.0のブランチ-非更新番号1.1.1の同じもので、 var rw = unescape(...)



違いは1つだけvar rw = unescape(...)



一般に、混乱のためにすべてが行われます。 したがって、最新バージョンは1.1.1であり、2.0ブランチとの違いを考慮に入れています。 Branch 2.0はそのタイトルに値しません。



ときどき、それをチェックするためのツールを使用して、ドキュメントを作成するのが便利です( 著者からのものがあります)。 (Webで読めるのは以下のリンクです。)要するに:



•彼は、アンダースコア_.template()



の「元の」構文を保持しました。この構文では、かっこ「 {{ ... }}



」内の任意のJSコードを記述できます。

•ブラケットは、設定ですべての正規表現を再定義することで再定義できます(通常は必要ありません)。

'it'



構造の上級要素の名前、および4つの論理動作設定も再定義できます。

•AMD、commonJS、およびそのグローバル名( 'doT'



)でサポートされます。

•基本的なユニバーサル構文に加えて、Mustache / Handelbarsスタイルに似たコマンドが多数あります。

•それらと同様に、 _.template()



は2段階のテンプレート(パラメーターのカリー化)があります-関数へ、そしてHTML(または他の)コードへ。

•HTMLの下で厳密にシャープ化されるのではなく、JSに結び付けられるため、その範囲はブラウザーとNodeJSです。

•ソースコード_.template()



よりもボリュームが大きくない-圧縮されていない圧縮形式で_.template()







(新しいまたは古いテンプレートエンジンのコードを使用した実験については、 http://jsfiddle.net/6KU9Y/2/の古い例を使用できます(ただし、jsフィードの方が優れています。)共通のテンプレートおよびデータで2つのエンジンをテストするための便利なページもリポジトリに構築されますtest/index.html



。デフォルトでは、デプロイおよび縮小されたバージョンのファイルと同じ結果を比較し、2番目のエンジンは'doT'



以外'doT'



グローバル名を持っている可能性があるため、クローンでのみ機能します。クローン、最初の場所、たとえば、元のDoT.js
1.1.1および解​​析の違いを参照してください。)



画像






2番目のエンジンのファイルで、ページを開く前に、名前globalName:'doTmin'



ます。



ただし、同じことをオンラインで行うのは難しくありません: https : //jsfiddle.net/spmbt/v3yvpbsu/26/embedded/#Resultまたはフレームとコード編集を使用し、大きな画面を持っている場合: https : //jsfiddle.net/spmbt/ v3yvpbsu / 26 / 。 ファイルを接続する必要はなく、DoT.jsの2つのバージョンの内容をコピーアンドペーストするだけです。2番目の方法では、クローンでこれを行う方が便利ですdoT



名をdoTmin



修正しdoTmin



(最小化されていなくても)。 デフォルトでは、DoT.js 1.1.1はオリジナルに設定され、DoT12.js 1.2.1はクローンです。



ベンチマーク(3番目のボタン)は短時間のために設計されているため、並列プロセスに依存し、同期アルゴリズムの速度は、多数の測定値を平均することで判断できます(平均が累積し、速度をわずかに判断できます)。 プロジェクトにはベンチマークが組み込まれていますが、Nodeを介して複雑であり、同じことを行います(テストファイルのグループに対して)。



自動更新チェックボックスとエラートラップはテストページに統合されているため、正常なバージョンでテストを実行できます。 したがって、配列での'~'



'@'



コマンドと'@'



コマンドの速度を比較するのは簡単です。 2番目も機能しますが、はるかに遅い-10〜15%([ベンチ]ボタンでチェック)。 これは、2番目のケースでより遅いfor-inループを使用する必要があるためです。 それでも、 '@'



コマンドを持たない元のバージョンの構造体から配列を準備する必要がないように、構造体のfor-inなしではできません。



すぐに伝統的に、2回目の計算( コンパイルされたテンプレートによる計算)は、毎回の完全なコンパイル (最初の数、100倍少ない測定) よりも 100倍高速です(短い式の場合 )。 スクリーンショットの「 Comp1e3: 99.22ms



」は、「 Comp1e3: 99.22ms



間に1000回の完全なコンパイルが実行されたこと」を意味します。 5行目の「 Run5e5: 69.08 ms



」は、「テンプレートによる5万の高速HTML生成が、1万世代ごとに平均Run5e5: 69.08 ms



」を意味します。



例のドロップダウンリストが追加れました。DoT.jsコマンドを使用した典型的な例を抽出し、2つのバージョンのスクリプトでテストできます。 サンプルへの変更は一時的に保存され、ブラウザページがリロードされていない場合、サンプルの前の段落を再選択することで元に戻すことができます。



チームについて-詳細



段落の先頭の引用符でDoT12.js



れた名前は、このテンプレート関数(コマンド)を担当するDoT12.js



コード内の正規表現の名前になります。



コマンド「 valEncEval



この名前の正規表現は、同様の構文を持つ3つの以前のチームを組み合わせたものです。



 {{     JS }}
      
      





アンダースコアの世界遺産。 これ以上は必要ありません。すべてを記述することは自給自足です(括弧間のスペースはオプションです)。 しかし、読むには... 40行以上を読むことは厳密には推奨されません。 JSオープンブラケットには、同じパターンで閉じられた同じテンプレートブレースが散在しています。 それらの背後には、閉じられていないHTMLタグがあります。 これは通常の方法であり、正常に動作し、マシンは理解しています。 同時に、Mustache / Handlebarsはすでに読み取り可能です。



 {{=  JS }}
      
      





式の値は周囲のHTMLストリームに配置され、HTMLタグは保持されますが、開始タグは括弧になります。 したがって、式の値に一致する"<br>"



は、ブラウザページにレイアウトされている場合、テキストとしてではなくタグとして動作し、HTMLルールに従って改行が発生します。



 {{!  JS }}
      
      





同じですが、HTMLコードの「セキュリティ」とともに出力にテキストを返します。htmlタグとhtmlエンコード( &...;



)文字はテキストに変わります。



コマンド「 条件付き



 {{? if- }} then- {{?}}
      
      





テンプレートの条件付きインクルード(括弧間のスペースはオプションです);



 {{? if- }} then- {{?? [if-else-]}} [if-]else- {{?}}
      
      





テキストテンプレートの分岐および条件付きチェーン。



式は、テンプレートモデレーション中にパラメーターが渡されるグローバル変数または'it'



という名前'it'



構造を含む任意の式です。



if-elseは、if-expressionを逆にすることで簡単に取得できます。 構文は、明らかに高速化のために複雑になりませんでした。



コマンドを使用



 {{# ,   }}
      
      





プリプロセッサの類似物(マクロ)-文字列には、最初に、ペアになっていないテンプレートブラケットを含むテキストのフラグメントを挿入できます。 結果がコンパイルされます。 たとえば、 {{# ...}}



を使用して、変数を介して別のテンプレートのテキストをテンプレートに入力できます。 しかし、チームは定義チームと対になって、より単純で具体的なケースを想定して考案されました。



コマンドを定義する



バージョン1.0から登場。 最初は、テンプレートのテキストではなく、設定後のパラメーターのリスト(doT.templateの3番目のパラメーター(テンプレート、設定、パラメーター))で決定されました。



「define」コマンドで「use」コマンドの変数を定義する形式は次のとおりです。

 {{## def.defin1 :___#}}  {{## def.defin1 =___#}} -    ()
      
      





変数にはドットと$を使用できます。変数には任意の行が定義されます。 いくつかのトリックがあります。



名前のドット(誰かのスタイルがコピーされた)。



最初の4文字が「def。」の場合、それらは削除されます。



コロンを介した場合、def [code] = {arg:param、text:v}のペアが書き込まれます。



平等により、関数 'def'が定義されます(例のリストにあるテストページを見ると便利です)。



1つの場所でマクロを定義して、2回以上使用できます。 すべてのマクロと同様に、コード品質の点で疑わしいです。 マクロが必要な場合、つまり、プロジェクトの観点からマクロを縮小する方法が間に合わなかったため、誰かが自分自身をシャットダウンして、汚れた方法でテキストのサイズを縮小する必要がありました。 また、スクリプトのリソースは変数の保存に費やされます。



いくつかのプラスは、いくつかのuse-useParamsコマンドのように、環境とスクリプトの作業場所が分離されていることです。



また、テンプレートをデータとリンクし、定義して使用する瞬間にスクリプトが実行されるという事実には意味的な違いがあります。 つまり、これらはマクロです。



コマンド「 defineParams



 {{##foo="bar"#}}
      
      





そのため、パラメーターは決定され、内部構造に蓄積され、その後何度も使用されます。



コマンド「 useParams

以前に定義されたパラメーターを使用します。



 {{#def.foo}}
      
      





JSでパラメーターを取得および定義することを妨げるものはありません。



 {{  JS }}
      
      





テンプレート環境と残りのJSを混在させたくないことを除きます。 この場合、IDEおよびエディターでの構文の強調表示とコード分析は失われます。 したがって、テンプレートテキストにJSを記述しない理由は他にもあります。



チーム「 反復



異なる速度と機能を持つ2つのチームを組み合わせます。 while-pattern {{~...}}



は、while whileループのループです。 (明らかに、私たちはすべてから選択し、その時点で最速のブラウザーを選択しました。)それは、アレイを介して実行できるfor-in-templateでの代替{{@...}}



よりも10-15%高速に動作します。構造によって。 4番目のパラメーター-式による要素のフィルタリング。 元のバージョンでは、配列のみがサポートされ、フィルタリングは行われません。 あなたには向いていません-常に「 {{ ... }}



」があります(Perlやマシンコードのように、書くのも読むのも便利です)。



 {{~ it : value : index : filter-expression }} while- {{~}}
      
      





ここit



、単語'it'



(または別の)、つまり最初の引数、配列のグローバル名、または配列を返す式です。 value



-引用符なしの'v'



または'value'



'v'



など'value'



任意の名前。これは、式{{= value+1}}



など、配列要素の置換値の代わりにforテンプレートで使用されます。 index



同様に、配列要素のインデックスを定義する名前。



はい、パラメータは「over the top」(最初の値、次にインデックス)で示されますが、そうなったので、ここでも次の同様のコマンドでも変更しません。 ロジックは、テンプレートで不要な場合はコロンとともに最後の(そして一般的に最後の) index



を省略できるということです。



クローンでは他のパラメーターを省略して、コロンを残すことができます。 オリジナルでは-それは不可能です。少なくとも手紙ですが、あなたは書く必要があります。 最初のデフォルトのパラメーターは 'it'(またはむしろtemplateSettings.varname



)で、残りにもデフォルトがありますが、非常に技術的で、記録されていません。



要するに、テンプレートのコンパイルと実行が可能な限り高速になるように、すべてが行われ、不要なアクションや美しいことはありません。 おそらく、あなたはまだ何かを改善することができ、いくつかのパフォーマンスの改善はコンパイル時間を悪化させるので、すべてにおいて合理的なバランスがあります。



 {{@ it : value : index : expression }} for-in- {{@}}
      
      





構造を最初のレベルで実行します。 ブラウザでは、配列よりも実行速度が遅くなります(10〜15%)。キー番号やその他のキーが発行される順序の特殊性を考慮する必要があります(番号が最初になり、次に他のすべてのキー(8番目以下、IEなどの古いバージョンを除く)。同じ過去形の古いFx。数字が他の行と連続した場所。) また、順序を保証する標準はありませんが、保証されています。 使用するか、チェックするか、配列に依存するかは開発者次第です。 最も評判の良い人は、100%を信頼することはできず、正しいと言うでしょう。 PythonとJSONの両方で同じ話。



同時に、JSONが来た順序または構造が定義された順序を使用すると、プロシージャコードの量が減ります。 4番目のパラメーターは、式(フィルター条件)を追加します。 falseの場合、要素は表示されません。 (条件がない場合、寄生条件"if(1)"



維持されますか?これはバランス料金です。)



パラメータの略語の例



 {{@::i}} for-in- {{@}}
      
      





それは、構造のすべての要素を通過するだけです。



例:



 {{@::i}} <i>{{=it[i]}}</i> {{@}}
      
      





とにかく



 {{@:v}} <i>{{=v}}</i> {{@}}
      
      





パターンの代わりに、 "@"



コマンドで配列を使用できます。 しかし、反対に、 "~"



-コマンド(配列で)-構造-オリジナルとの互換性のために不可能です。



... 7年後、これらはすべて消滅し、新しい壮大なフレームワークの重みで消滅します。そこでは、問題が独自の方法で別の方法で解決されます。 forEach、filter、reduce、JSX-テンプレートキラーはすでにしきい値を超えており、ドアのこちら側にそれぞれ1フィートあります。 また、チンパンジーでも画面レイアウトを管理できます。 それまでの間、松葉杖をいじくりまわして、ついにK155LA3のような物語になります。



どんな設定があり、なぜ必要なのか



 varname: 'it',
      
      





この設定は非常に簡単です。 テンプレート式では、引数[0](中間コンパイル済み関数の最初のパラメーター)の代わりに名前が使用されます。 引数[0]は、ネストされた関数のために常に適用可能とはほど遠く、競合がない場合、名前はほとんど常にです。 現在、競合がある場合、名前はライブラリテンプレートエンジンのコードで直接変更できるだけでなく、悪いことに加えて、現在のコマンドのローカル設定の2番目のパラメーターdoT.template()



でも変更できます。 ( window.doT.templateSettings



を介してwindow.doT.templateSettings



ことにより、設定を「静的に」変更する方法もあります。)



このテンプレートエンジンには、競合を引き起こす可能性のある他の特定の名前があります。 テストページtest/index.html



[関数を表示]ボタンをクリックすると、テストページで簡単に確認できます。 これらは名前です: out, arr1, arr2



、...、ll(2つの小さなL)、v、i(配列を通過するとき。同じ外部名をスクリーニングします。しかし、 it



は特別なアカウントにあり、それなしではどこにもありません。設定で。



 strip: true,
      
      





余分なスペース、タブ、改行を捨てます。 出力テキストのフォーマットが重要でない場合は、trueを使用します。 関数とテンプレートは短くなり、コンパイル速度は奇妙に思えるかもしれませんが、わずかに遅くなります(1〜2%)。 パフォーマンス-速度で区別できません。 すなわち コンパイルを高速化するには、 strip: false



設定しstrip: false







 append: true,
      
      





HTMLコードとデータの断片をout変数に追加するスタイルは、チェーンで合計するか、演算子を割り当てます。 後者は関数のテキストを長くするため、特に必要ない場合はtrueを選択します。 (どうやら、これはかつて疑問でした-何を選択し、何がより速く動作するか。)



 log: true,
      
      





使用されません。 削除するのを忘れたか、NodeJS-expressなどの近隣のスクリプトのどこかが必要です。



 selfcontained: false,
      
      





最適化について少し説明します。 doT.template(...)



関数は、1つの共通環境( _globals



)で準備し、すぐにdoT.template(...)(...)



として実行することも、 doT.template(...)(...)



に実行することもできます(ajaxまたはファイルから実行) 。 後者の場合、true(関数doT.template(...)を拡張する)が必要です。通常、最初の場合はfalseです。 その後、過剰に生成する必要はなく、カウントは_globals.doT.encodeHTMLSource()



から生成された_globals._encodeHTML



に格納され_globals._encodeHTML



、常にではありませんが、 {{! }}



{{! }}







言い換えると、 selfcontained = true



は、テンプレート関数doT.template()



doT.template()



とは別に使用されることを意味するため、テンプレート実行のためのすべてを含める必要があります。 それだけです- {{!}}



コマンドでHTML文字をエンコードする特別な場合のみを意味します。 存在する場合は、エンコード関数の定義を関数に含める必要があります—作成doT.encHtmlStr



行(これはクローン1.2.1で行われ、オリジナルでは、 encodeHTMLSource



関数encodeHTMLSource



文字列に変換されます)。



オリジナルのバージョン1.1.1には欠陥がありますselfcontained = false



場合でも、アルゴリズムは常に圧縮せずに関数コードをテンプレートに「固定」します。これは修正する必要がありました。 この関数は、 doNotSkipEncoded



パラメーターを常にバインドすることも処理しますが、これはテンプレート関数を作成する場合にのみ必要です。



次に、元のエンジンでは、グローバルオブジェクト(ウィンドウ、グローバル)を使用してHTMLエンコード機能の使用を最適化するため、バージョンの競合の問題があります。 クローン1.2.1では、エンコード関数のグローバル名がエンジンの名前とバージョンに応じて選択されたという事実によって解決されました。 次のような結果になりました。



 var encHt = '_'+dS.globalName + doT.version.replace(/\./g,''). ... encHtmlStr:'var encodeHTML=typeof '+ encHt +'!="undefined"?'+ encHt +':function(c){return((c||"")+"").replace(' + (dS.doNotSkipEncoded ?'/[&<>"\'\\/]/g':'/&(?!#?\\w+;)|[<>"\'/]/g') +',function(s){return{"&":"&","<":"<",">":">",\'"\':""","\'":"'","/":"/"}[s]||s})};'
      
      





テンプレート関数に挿入する文字列を取得しますが、 selfcontained = false



場合は{{! }}



{{! }}



、それからencodeHTML()



を使用するために、グローバルオブジェクトで実行するように制限します。



 doNotSkipEncoded: false,
      
      





doT.encodeHTMLSource()



引数。 {{! }}



{{! }}



-安全な(実行可能なタグなしの)HTMLコードを発行します。 環境テンプレートにある場合、安全な文字を生成する_globals._encodeHTML



関数が初めて定義され、繰り返し呼び出しを保存します。 このようなバグを解決するために作られました: github.com/olado/doT/issues/106 trueの場合、 "&....;"



などのすべてのコードはエンコードされません 、および主な結果は、そのような式の'&'



アンパサンドの非コーディングです。



おわりに



コンパイル速度のために、必要なアクションが少ないパラメーターが明らかに必要です:可能であれば、 selfcontained = false



strip: false



append: true



。 残りのdoTパーツは最適化されており、平均して最速のソリューションが選択されています。 バージョンの速度はテンプレートの特定のタイプに依存するため、速度に関するステートメントはタスクの範囲でのみ平均化できます。



doNotSkipEncoded



は、 {{!...}}



コマンドの結果に影響を与えますtrue



&...;



という形式のエンコードされた文字&...;







一般に、いくつかのバグを解決するために実行する必要のあるコード分析の量が増加するため、クローンはテンプレートを関数にコンパイルします。 たとえば、unescape()関数が拡張されています。 最後の2つの置換を削除すると、速度は3%増加します(Chrome v.61 Canary)が、いくつかのバグがあります。



パーセント単位に注意を払わない場合、doT.jsテンプレートエンジンは最速でありながらコンパクトです。 ES6は、配列の新しいメソッドを使用しません-それは間違った時代に書かれました。これは、すべてのブラウザーでサポートされているという点でプラスになります(IE8でも動作するはずです)。 IE11でテスト済み。テストページでは、test.index.htmlがperformance.now()



ポリフィルされています。



DoTのためのバージョン、テスト、メモリのベンチマークを比較• - DoT12:https://jsfiddle.net/spmbt/v3yvpbsu/26/embedded/#Result - :DoT12•のDoTのためのバージョン、テスト、メモリのベンチマーク比較のhttps:// jsFiddle。 net / spmbt / v3yvpbsu / 26 / embedded /#結果またはフレームとコード編集:https



: //jsfiddle.net/spmbt/v3yvpbsu/26/•Github DoT12.js(オリジナルのクローン)、DoT.js

JSFiddleは、テンプレートエンジン(2013コード)とテンプレート(Dotクローンが最初に導入されました。他の隣接するフィード番号では、読者は実験結果を残すことができます。 「実行」)。

パフォーマンステストを含む2013 DoT.jsクローンに関する記事



* Closure Compiler -AdvancedモードではUglifyよりも圧縮率が少し高くなります。

* doT.jsの使用(適切な例、2012年)

* doT.js:dot.js内の if-else ifのチェーンif-elseチェーンの作成方法。

* 著者のサンドボックスを使用した詳細なドキュメントと、リンク上の説明例。



All Articles