AngularJS1.2から1.4ぞの移行、パヌト2

最初の郚分では、新しいバヌゞョンぞの移行の䞻な問題をすべお怜蚎したしたが、これで䜕をしたのかに぀いお觊れたす。


画像


前述のように、移行の䞻な理由は、アプリケヌションの速床が倧幅に向䞊したこずですJeff CrossずBrian FordがngEurope䌚議で述べたように、DOMでの操䜜が4.3倍、 $digestサむクルが3.5倍1.2ず比范 。


ただし、この速床は䞻に内郚の最適化ず魔法によるものではなく、コヌドをより効率的に蚘述できるツヌルの提䟛によるものです。


これらのツヌルを芋おみたしょう


デバッグ情報


アンギュラヌがリ゜ヌスの倧郚分を、クラスの远加などのデバッグを容易にする情報に費やしおいるこずはニュヌスではありたせん
DOM芁玠 ng-bindingおよびng-isolated-scopeクラスなどたたはそれらにさたざたなメ゜ッドをアタッチしおscopeにアクセスしscope たずえば.scope()および.isolateScope() 。


これらはすべお、分床噚やバタランなどのツヌルの䜜業に圹立ち、必芁ですが、このデヌタは生産に必芁ですか


バヌゞョン1.3以降、デバッグ情報を無効にできたす。


 app.config(['$compileProvider', function ($compileProvider) { $compileProvider.debugInfoEnabled(false); }]); 

しかし、補品を販売する必芁があり、デバッグが無効になっおいる堎合はどうでしょうか


ここでは、 angularオブゞェクトの.reloadWithDebugInfo()メ゜ッドが保存され、 angularオブゞェクトはグロヌバルなので、コン゜ヌルからこのコヌドを簡単に実行できたす。


 angular.reloadWithDebugInfo(); 

$ applyAsync


バヌゞョン1.3では、 $applyAsyncサヌビスが$applyAsyncれたした。倚くの点で、そのメカニズムは既存の$evalAsyncサヌビスず䌌おいたす。


簡単に蚀えば、匏をキュヌに远加しおから埅機しsetTimeout...、0を蚭定し、最新のブラりザヌでは玄10ミリ秒です、過去に別の匏がキュヌに远加されおいない堎合は、開始したす
$rootScope.$digest() 。


これにより、同じ$ダむゞェストルヌプで実行され、$ applyを頻繁に呌び出すこずを心配せずに、DOMに圱響する倚くの同時匏を実行できたす。


$ evalAsyncずの違いは䜕ですか


䞻な違いは、 $applyAsync自䜓がダヌティチェックの前に$digestサむクルの開始時に匏キュヌ党䜓を実行するこずです。これにより、 $evalAsyncはダヌティチェック䞭に実行され $evalAsync より正確には、 ダヌティチェックサむクルの開始、およびキュヌに远加された匏$りォッチの倖郚は、$ダむゞェストサむクルを再び開始したす。これにより、同じ$digest匏が繰り返し実行されたす。


[詳现]


ただし、このツヌルを䜿甚するこずの本圓の利点は、角床の内郚サヌビス、たずえば$httpProviderたす。


$ http


$httpサヌビスずXHRリク゚ストを行う他の方法ずの䞻な違いは、完了時に$apply呌び出すこずです。


問題は倚くの䞊列ク゚リであり、それぞれが完了時に$applyし、ブレヌキに぀ながりたす。


この問題は、バヌゞョン1.3の $applyAsyncの到着により解決されたした。


 app.config(function ($httpProvider) { $httpProvider.useApplyAsync(true); }); 

このコヌドには、 $applyAsync内での$httpProvider $applyAsync䜿甚が含たれ$applyAsync 。


これにより、同時芁求のすべおの玄束がresolvedずきに1回だけ$ applyを実行でき、パフォヌマンスが倧幅に向䞊したす。


䞀床バむンド


AngularJSの䞻なパフォヌマンスの問題の1぀は、双方向のバむンディングがすべおの匏に適甚されたすが、すべおのデヌタがそれを必芁ずするわけではないずいう事実に起因する$watchの膚倧な量です。


静的デヌタの堎合、䞀晩バむンドするだけで十分であり、カスタムディレクティブによっおこれが決定される前に、バヌゞョン1.3ですべおが倉曎されたした。


バヌゞョン1.3以降、新しい構文は、匏の先頭に::の圢匏で䜿甚できたす。


::始たる匏は䞀方向のバむンディングずしお認識され、匏のデヌタが安定しお最初の$digestサむクルが経過するずすぐに远跡監芖解陀されなくなりたす。


䟋


 {{:: foo }} <button ng-bind=":: foo"></button> <ul> <li ng-repeat=":: foo in bar"></li> </ul> <custom-directive two-way-bind-property=":: foo"><custom-directive> 

デヌタの安定性


デヌタは、 undefined限り䞍安定であるず芋なされたす。 NaN 、 false 、 '' []たたはnullいずれであっおも、他のデヌタは安定しおいるず芋なされ、 unwatch匏になりたす。


これは、最初の$ダむゞェストサむクル䞭に利甚できない静的デヌタに必芁です。


たずえば、デヌタがサヌバヌから送信undefinedれた堎合、リク゚ストを埅機しおいる間、倉数の倀をundefinedたたにするこずができたす。 この間ずっず、この匏のりォッチャヌは存続し、 undefined以倖のデヌタをむンストヌルした埌にのみ、その結果を返したす。


::を含む匏を定数ずしお扱いたす。䞀床蚭定するず、倉曎できなくなりたす。


曎新䞍可の曎新


100のうち99のケヌスで曎新されない匏があるず仮定したす぀たり、オヌバヌりォッチでそれに陥るこずはありたせんでしたが、堎合によっおは必芁になりたす。 になる方法 バむンドワンス匏を匷制的に曎新できるかどうか疑問に思いたした。


いいえ、できたせん:)ただし、独自の属性ディレクティブを䜜成しお、特定のむベントに応じおディレクティブ党䜓を再コンパむルするように匷制できたす。 ここに䟋がありたす 。




パフォヌマンスのこの郚分は終了し、玠敵な利点に぀いお話すこずができたす。


ngModelオプション


バヌゞョン1.3では、 ng-modelに加えお、モデルが曎新されるタむミングを担圓ng-model補助ディレクティブng-model-options導入されたした。


曎新時間は2぀の芁因に䟝存したす。


1 updateOnモデルが曎新される特別なむベントむベント。たずえば、 blur 、 clickたたはある皮のカスタムむベントです。 デフォルトは垞にdefault 。぀たり、各コントロヌルは独自のむベントを䜿甚したす。 {event: "default customEvent"}むベントを远加しお暙準むベントを拡匵するdefaultは、リストにdefaultを远加するこずを忘れないでください䟋 {event: "default customEvent"} 。


2 debounce -新しいデヌタを芋越しおモデルを曎新するずきの遅延デフォルトは0、぀たり即時。 入力{debounce: 300}を指定し、300ミリ秒未満の間隔で3文字を入力するず、モデルおよびさたざたなモディファむダ/バリデヌタが䞀床だけ曎新されたす。 さらに、 debounceをむベントず組み合わせお、各むベントの遅延を瀺すこずができたす。䟋 {event: "default customEvent", debounce: {default: 0, customEvent: 400}} 。


これにより、倚くの自転車をなくすこずができさよならsetTimeout / clearTimeout、パフォヌマンスが倧幅に向䞊し $digest 、 $watchersすべおの$watchersの無駄な再起動が$watchers 、たた非同期怜蚌の誀怜知の数が枛りたすただし、 $httpこのサヌビスは、リク゚ストをスパムしないように十分にスマヌトですが、安定したデヌタを埅ちたす。


しかし、さらに3぀の䟿利なオプションがありたす。


allowInvalidフラグを䜿甚するず、倀が無効な堎合でも$modelValueを蚭定できたす デフォルトでは、倀は無効ですが、 undefinedモデルに曞き蟌たれたす。これにより、たずえば䞭間倀を芋぀けるこずができたせん


setterGetterフラグを䜿甚するず、独自の関数をngModelずしお蚭定できたす 。これはngModel.viewValue ngModel.modelValueずngModel.viewValue間の䞀皮であり、セッタヌおよびゲッタヌずしお機胜したす。 plunkerのラむブ䟋 。


タむムゟヌンを䜿甚するず、時間 dateたたはtime に関連するコントロヌルのタむムゟヌンを蚭定できたす。たずえば、 '+0430'は「4時間30分GTM」を意味したす。 デフォルトでは、ブラりザのタむムゟヌンが䜿甚されたす。


updateOnずデバりンスを無芖する


モデルを手動で蚘録する堎合、むベントで蚭定された遅延を無芖しお、すぐに曎新を実行する必芁がある堎合がありたす。 これにはngModelCtrl.$commitViewValue()メ゜ッドがありたす。


倉曎をキャンセル


debounceプロセス䞭にハングしおいるすべおの倉曎を元に戻したい堎合、ビュヌをモデルの珟圚の状態に調敎するメ゜ッド$rollbackViewValue() 以前の$cancelUpdate() がありたす。


この機胜の䜿甚䟋ずしお、公匏ドキュメントには入力があり、ESCを抌すず倉曎をロヌルバックできたす。


詳现なドキュメント


怜蚌


ナヌザビリティの面での䞻芁な改善点の1぀は、フォヌムの怜蚌です。


以前は、 ndModel.$formattersおよびndModel.$parsersを介しお怜蚌メカニズムを実装する必芁があり、 ndModel.$setValidity()を介しお怜蚌結果に盎接圱響し、非同期チェックの実装は別の喜びでした。


むノベヌションはパフォヌマンスにも圱響したした。


実際、DOM $parsers たたはモデル $formatters で曎新されるたびに、以前に怜蚌されおいた関数が起動され、しばしば互いの倀に圱響を䞎え、怜蚌サむクルを再開したした。


新しいバヌゞョンでは、モデルが倉曎され、このモデルに゚ラヌがない堎合 {parse: true にのみ怜蚌が開始され{parse: true 。 モデル自䜓たたはバリデヌタヌ内のコントロヌルの衚珟ぞの圱響も排陀され、アプリケヌションの速床にプラスの圱響を䞎えたす。


$フォヌマッタヌおよび$パヌサヌずは䜕ですか、なぜ䜜成されるのですか それらは削陀されたすか

いいえ、削陀されたせんでした。これらは他の目的のための他のツヌルであり、ただ必芁です。


$formattersず$parsersはどちらも、倀を受け取り、チェヌンに沿っお次のハンドラヌ関数に枡すハンドラヌ関数を含む配列です。 チェヌン内の各リンクは、倀を倉曎しおから枡すこずができたす。


$フォヌマッタヌ
モデルが倉曎されるたびに、 $formattersは配列内のハンドラヌを逆の順序末尟から先頭で$formattersたす。 最埌に枡された倀は、DOMでモデルがどのように衚珟されるかを決定したす。 蚀い換えるず、 $formattersはngModelCtrl.$modelValueがngModelCtrl.$modelValueに倉換される方法を担圓したす。


$パヌサヌ
コントロヌルがDOMから倀を読み取るたびに、 $parsersはハンドラヌの配列を最初から最埌たで$parsers 、チェヌンに沿っお倀を枡したす。 最埌に枡された倀は、モデルで倀がどのように衚珟されるかを決定したす。 蚀い換えるず、 $parsersはngModelCtrl.$viewValueがngModelCtrl.$viewValueに倉換される方法を担圓したす。


どこで䜿甚されおいたすか
たず第䞀に、アングル自身が圌の䜜品でそれらを䜿甚しおいたす。 たずえば、最小長の怜蚌を䜿甚しおコントロヌルを䜜成し、 $formattersチェックするず、空ではないが、DOMから文字列に倀を倉換するラッパヌ関数が既に含たれおいるこずがわかりたす。


䞊蚘の䟋は、厳密に定矩された圢匏でのみモデルに倀が入っおいるこずを確認したい堎合、ハンドラヌを䜿甚しお倀を前凊理サニタむズしたす。


他の2぀の䞀般的な䜿甚方法は、倀の双方向フィルタリングたずえば、ナヌザヌが入力に「10,000」を入力し、「10000」がモデルに保存され、その逆の堎合ずマスクの䜜成ナヌザヌが電話マスク「+7000 000-00-00 "、およびモデルに保存する" 70000000000 "。


䟋からわかるように-䞍可欠なツヌル。


怜蚌は以前どのように機胜したしたか

叀い怜蚌方法に関する包括的な情報は、Habréに関する次の蚘事から入手できたす。



将来、叀い怜蚌方法を䜿甚しないのはなぜですか

事実は、 ndModel.$parsersからundefinedを返すこずですndModel.$parsersは、 ngModelCtrl.$modelValueを公​​開し、 ngModelCtrl.$modelValueをundefinedに公開し、 ngModelCtrl.$modelValue {parse: false}をngModelCtrl.$modelValue 障害フィヌルド。


この堎合、バリデヌタヌ $validatorsず$asyncValidators は䜜業を開始したせん。


allowInvalidフラグをtrue蚭定するこずにより、 ngModelOptionsこの動䜜を無効にできtrue 。


バヌゞョン1.3から 、䟿利な同期および非同期怜蚌のためのツヌルが甚意されたした。


たた、新しいバリデヌタヌの䜜業はモデルの曎新に関係しおいるため、䞊蚘のngModelOptionsにも䟝存しおいるこずにも蚀及する䟡倀がありたす。


同期


同期怜蚌の堎合、新しいバヌゞョンはndModel.$validatorsコレクションを提䟛し、怜蚌関数で拡匵したす。


バリデヌタ関数は、有効な倀ず無効な倀に察しおそれぞれtrueたたはfalseを返す必芁がありたす。


䟋


  ngModel.$validators.integer = function(modelValue, viewValue) { // ,      if (ctrl.$isEmpty(modelValue)) { return true; } if (INTEGER_REGEXP.test(viewValue)) { return true; //   } return false; //    }; 

非同期


非同期怜蚌の堎合は、 ngModelCtrl.$asyncValidatorsコレクションが䜿甚され、同じロゞックが怜蚌関数でそれを拡匵したす。


非同期バヌゞョンの䞻な違い



AngularJSの玄束は、特別なサヌビス$q 、基本的に$q䜿甚する$q $timeoutや$httpなどのサヌビスによっお生成されたす。


このコレクションには、1぀のバリデヌタヌによっお返される耇数のプロミスが含たれおいたせん。 ぀たり、怜蚌を数回呌び出すず、以前のプロミスの結果に関係なく、バリデヌタヌの最埌の呌び出しからのプロミスのみが考慮されたす。


バリデヌタヌがプロミスを枡しおから解決するたで resolve()たたはreject() 、 ngModelCtrl.$pendingフィヌルドにはバリデヌタヌ名が栌玍され、 ngModelCtrl.$valid ngModelCtrl.$invalidおよびngModelCtrl.$invalidはundefined


この機胜には泚意しおください怜蚌がFormCtrl.$errorsおいる限りFormCtrl.$errorsフォヌムは無効になりたすが、 FormCtrl.$errors Errorsにぱラヌが衚瀺されたせんが、 FormCtrl.$pendingは「保留䞭」のバリデヌタがFormCtrl.$pending 。


䟋
  ngModelCtrl.$asyncValidators.username = function(modelValue, viewValue) { // ,      if (ctrl.$isEmpty(modelValue)) { return $q.when(); } var def = $q.defer(); //    $timeout(function() { if (usernames.indexOf(modelValue) === -1) { def.resolve(); //  ,   } else { def.reject(); //  ,    } }, 2000); return def.promise; }; ngModelCtrl.$asyncValidators.uniqueUsername = function(modelValue, viewValue) { var value = modelValue || viewValue; // ,     return $http.get('/api/users/' + value). then(function resolved() { //  ,   ,     return $q.reject('exists'); }, function rejected() { //   ,  ,    return true; }); }; 

倀修食子を䜿甚するフィヌルドで $formattersおよび$parsersを介しお非同期怜蚌を慎重に䜿甚するこずは䟡倀がありたす。これにより、耇数の操䜜、およびフィヌルドの誀った怜蚌たたは無効化が発生する可胜性がありたす。


そのような堎合の怜蚌䟋
 var pendingPromise; ngModelCtrl.$asyncValidators.checkPhoneUnique = function (modelValue) { if (pendingPromise) { return pendingPromise; } var deferred = $q.defer(); if (modelValue) { pendingPromise = deferred.promise; $http.post('/', {value: modelValue}) .success(function (response) { if (response.Result === '   ') { deferred.resolve(); } else { deferred.reject(); } }).error(function () { deferred.reject(); }).finally(function () { pendingPromise = null; }); } else { deferred.resolve(); } return deferred.promise; }; 

ngMessages


ngMessagesモゞュヌルngMessages 、ペヌゞ䞊のメッセヌゞの衚瀺を容易にするように蚭蚈されおいたす。


このモゞュヌルはペヌゞ䞊のあらゆるメッセヌゞに䟿利に䜿甚できるずいう事実にもかかわらず、通垞はフォヌムの゚ラヌを衚瀺するために䜿甚されたす。 このツヌルが解決する問題を理解するために、゚ラヌを衚瀺する叀い方法の苊痛を芋お、それを新しいものず比范したしょう。


比范の䟋ずしお、このフォヌムを䜿甚しおコメントを远加したす。


 <form name="commentForm"> <ul class="warnings" ng-if="commentForm.$error && commentForm.$dirty"> ... </ul> <label>:</label> <input type="text" name="username" ng-model="comment.username" required> <label>:</label> <textarea name="message" ng-model="comment.message" minlength="5" maxlength="500"></textarea> </form> 

怜蚌の実装はそのたたにしお、必芁な条件に関するメッセヌゞの衚瀺のみを考慮したす。



叀い゚ラヌ衚瀺方法


この䟋は長く出おきたので、私はそれをネタバレの䞋に隠したした。

次に、これらのフィヌルドの゚ラヌを衚瀺する方法を想像しおください。


 <form name="commentForm"> <ul class="warnings" ng-if="commentForm.$error && commentForm.$dirty"> <span ng-if="commentForm.message.$error.minlength">      5  </span> <span ng-if="commentForm.username.$error.maxlength">      500  </span> <span ng-if="commentForm.username.$error.required">    </span> </ul> <label>:</label> ... <label>:</label> ... </form> 

たあ、物事がそれほど悪くない限り、そうですか
しかし、なぜニックネヌムのメッセヌゞずコメントがすべお䞀床に衚瀺されるのですか 順次衚瀺を远加しおこれを修正したしょう。


 <form name="commentForm"> <ul class="warnings" ng-if="commentForm.$error && commentForm.$dirty"> <span ng-if="commentForm.message.$error.minlength && commentForm.username.$valid">      5  </span> ... </ul> <label>:</label> ... <label>:</label> ... </form> 

あなたはただ「これはそれほど悪くない」ず思いたすか ペヌゞのフィヌルドが2ではなく20であり、それぞれに少なくずも5぀の投皿があるず想像しおください。 同様のスタむルで、私たちのペヌゞはすぐに状況が倉わるずゎミ箱に倉わりたす。


もちろん、このタスクを実装するためのベストプラクティス、 FormControllerの動䜜を拡匵する特別なディレクティブおよび束葉杖がありFormController たずえば、プロゞェクトでは、珟圚の゚ラヌを栌玍するすべおのコントロヌルがshowErrorプロパティで拡匵されたした 。


新しい゚ラヌ衚瀺方法


接続

ngMesssages別のモゞュヌルずしお提䟛されおおり、䜜業を開始する前に接続する必芁がありたす。 パッケヌゞマネヌゞャヌを䜿甚しおモゞュヌルをダりンロヌドたたはむンストヌルし、プロゞェクトに接続したす。


 <script src="path/to/angular-messages.js"></script> 

䟝存する远加


 angular.module('myApp', ['ngMessages']); 

このモゞュヌルの基本的な䜜業は、2぀のディレクティブを䜿甚するこずです。


  1. ng-messagesを含むコンテナ
  2. ng-message盎接ng-message

ng-messagesは、匕数ずしお、 ng-messagesがチェックおよびng-messagesされるキヌのコレクションを受け取りたす。これらのキヌは、比范のための匕数ずしお文字列たたは匏を受け取りたす 1.4から開始。


コメントを远加するための同じフォヌムの䟋を繰り返したすが、 ngMessagesたす。


 <div ng-messages="commentForm.message.$error" class="warnings"> <p ng-message="minlength">      5  </p> <p ng-message="maxlength">      500  </p> <p ng-message="required">    </p> </div> 

ngMessagesは芁玠ずしおngMessages䜿甚できたす


 <ng-messages for="commentForm.message.$error" class="warnings"> <ng-message when="minlength">      5  </ng> <ng-message when="maxlength">      500  </ng> <ng-message when="required">    </ng> </ng-messages> 

したがっお、 ngMessagesはすぐに2぀の問題を解決したした。



さらに、メッセヌゞ出力の優先順䜍付けの問題にも察凊しおいたす。 ここではすべおが簡単です。メッセヌゞは、DOM内の堎所に埓っお衚瀺されたす。


耇数のメッセヌゞ出力を有効にするには、 ng-messages-multiple属性をng-messages-multipleディレクティブに远加しng-messages-multiple 。


 <ng-messages ng-messages-multiple for="commentForm.message.$error"> ... </ng-messages> 

– ngMessages , , , :


, 1.4, 1.3

1.3 ng-messages-include ng-messages , ng-messages-include ng-message :


1.3


 <ng-messages ng-messages-include="length-message" for="commentForm.message.$error"> </ng-messages> 

1.4+


 <ng-messages for="commentForm.message.$error"> <ng-messages-include="length-message"></ng-messages-include> </ng-messages> 

(, ) , :


 <script type="script/ng-template" id="length-message"> <ng-message when="minlength">     </ng-message> </script> ... <ng-messages for="commentForm.message.$error"> <ng-messages-include="length-message"></ng-messages-include> </ng-messages> <ng-messages for="anotherForm.someField.$error"> <ng-messages-include="length-message"></ng-messages-include> </ng-messages> 

, , . .


, 1.4 , ng-message-exp :


 // error = {type: required, message: '    '}; <ng-messages for="commentForm.message.$error"> <ng-message-exp="error.type"> {{ error.message }} </ng-message-exp> </ng-messages> 

ng-message-exp , ng-message , ( expression ). , , , AJAX .


– . ng-messages !


:



コントロヌラヌ


bindToController


[]


, controller as , scope .


, this.something . .


:


 app.directive('someDirective', function () { return { scope: { name: '=' }, controller: function () { this.name = 'Foo' }, controllerAs: 'ctrl' ... }; }); 

name .


:


  $scope.$watch('name', function (newValue) { this.name = newValue; }.bind(this)); 

, , , , ?


1.3 :


bindToController .


 app.directive('someDirective', function () { return { scope: { name: '=' }, controller: function () { this.name = 'Foo' }, bindToController: true, ... }; }); 

ctrl.name $scope.name .


1.4 :


 app.directive('someDirective', function () { return { scope: true, bindToController: { name: '=' }, controller: function () { this.name = 'Foo' }, ... }; }); 

scope bindToController .


, bindToController , , , scope , scope .


- scope , true . bindToController scope .


フィルタヌ


 {{ expression | filter }} 


, , «» ( expression ), ( filter ). , , , .


1.3 : , . , , $digest , , . , , .


plunker


: , , - ? , , «» , ?


このため、静的 stateless および動的 stateful フィルタヌの抂念は1.3で導入されたした。 デフォルトでは、フィルタヌはstatelessように動䜜したす。 , $stateful true .


䟋


 angular.module('myApp', []) .filter('customFilter', ['someService', function (someService) { function customFilter(input) { //     someService input += someService.getData(); return input; } customFilter.$stateful = true; return customFilter; }]); 

重倧な倉曎
泚意深い読者は、そのような倉曎が実際に叀い動的フィルタヌの動䜜を壊す可胜性があるこずに気付いおいるかもしれたせん。 残念ながら、最初の郚分でこの機胜を説明するのを忘れおいたしたが、そのような機䌚は怜蚎する䟡倀がありたす。


dateFilter


weeks


おわりに


それだけです - , .


, .


, markdown. - html.


, , :)


画像



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


All Articles