$ apply()および$ digest()は、Angularjsの2つのコアコンセプトですが、時には混乱しています。 Angularjsの仕組みを理解するには、まず$ apply()と$ digest()がどのように機能するかを理解する必要があります。この記事は、$ apply()と$ digest()が何であるか、そしてそれらが日常のエンコーディングでどのように適用されるかを説明することを目的としています。
1。$ apply()と$ digest()を探索します
1.1。双方向のデータバインディングと$ watch()を理解します。
AngularJSは、双方向データバインディングと呼ばれる非常にクールな機能を提供します。これにより、コードの作成方法が大幅に簡素化されます。データバインディングとは、ビュー内のデータが変更されると、変更がスコープデータに自動的に返送されることを意味します。つまり、スコープモデルが自動的に更新されます。同様に、スコープモデルが変更されると、ビュー内のデータが最新値に更新されます。では、Angularjsはこれをどのように行いますか? {{amodel}}のような式を書くと、AngularjsはScopeモデルでウォッチャーを設定します。これは、データが変更されたときにビューを更新するために使用されます。ここのウォッチャーは、Angularjsで設定するウォッチャーと同じです。
$ scope。$ watch( 'amodel'、function(newValue、oldValue){// newValueでdomを更新});$ watch()に渡された2番目のパラメーターはコールバック関数であり、アモデルの値が変更されたときに呼び出されます。 Amodelが変更された場合、このコールバック関数がビューを更新するために呼び出されることを理解することは難しくありませんが、まだ非常に重要な問題があります! Angularjsは、このコールバック関数をいつ呼び出すかをどのようにして知っていますか?言い換えれば、AngularjsはAmodelが変更されたことを知っているときに、対応するコールバック関数をどのように呼びましたか?スコープモデルのデータが変更されたかどうかを確認するために、定期的に関数を実行しますか?まあ、それは$ DIGESTループが入ってくるところです。
$ digestループでは、ウォッチャーが解雇されます。ウォッチャーがトリガーされると、AngularJSがスコープモデルを検出します。変更された場合、ウォッチャーに関連付けられたコールバック関数が呼び出されます。では、次の質問は、$ダイジェストループがさまざまな方法でいつ始まるのかということです。
$ scope。$ digest()を呼び出した後、$ digestループが始まります。 NGクリック指令に対応するハンドラー関数のスコープのデータを変更すると、AngularJSは$ Digest()を呼び出すことにより$ Digestループを自動的にトリガーします。 $ digestループが始まると、各ウォッチャーがトリガーされます。これらのウォッチャーは、範囲内の現在のモデル値が前回計算されたモデル値と異なるかどうかを確認します。異なる場合、対応するコールバック関数が実行されます。この関数を呼び出す結果は、ビュー内の式の内容(翻訳者の注:{{amodel}}など)が更新されます。 NGクリックディレクティブに加えて、モデル(NGモデル、$タイムアウトなど)を変更し、$ダイジェストループを自動的にトリガーするための他の組み込みディレクティブとサービスがあります。
これまでのところ悪くはありません!ただし、小さな問題があります。上記の例では、Angularjsは$ digest()を直接呼び出すのではなく、$ scope。$ apply()を呼び出します。したがって、$ DIGESTループは$ Rootscopeから始まり、すべての子供スコープウォッチャーにアクセスします。
注:$ scope。$ apply()は、$rotscope。$ digest()を自動的に呼び出します。
$ apply()メソッドには2つのフォームがあります。
最初のものは、パラメーターとして関数を受け入れ、関数を実行し、$ダイジェストループをトリガーします。
2番目のタイプはパラメーターを受け入れず、$ダイジェストループをトリガーします。なぜ最初のフォームが優れているのか、すぐにわかります。
1.2。 $ apply()メソッドを手動で呼び出すのはいつですか?
AngularJSが常にコードを関数に包み、$ Apply()に渡して$ Digestループを起動する場合、いつ$ Apply()メソッドを手動で呼び出す必要がありますか?実際、AngularJSには非常に明確な要件があり、AngularJSコンテキストで発生する変化に自動的に応答することのみが責任を負います(つまり、$ Apply()メソッドで発生するモデルの変更)。これは、AngularJSの組み込み指令がどのように行うかであるため、モデルの変更はビューに反映されます。ただし、AngularJSコンテキストの外側の場所でモデルを変更する場合、$ Apply()を手動で呼び出すことにより、AngularJSに通知する必要があります。 Angularjsに、いくつかのモデルを変更したことを伝え、AngularJがウォッチャーが正しく対応するのに役立つことを願っています。
たとえば、JavaScriptでSettimeout()を使用してスコープモデルを更新する場合、AngularJSには変更が何を変更したかを知る方法がありません。この場合、$ apply()を呼び出し、それを呼び出して$ダイジェストループをトリガーするのはあなたの責任です。同様に、DOMイベントリスナーを設定し、そのリスナーのいくつかのモデルを変更する指令がある場合は、変更がビューに正しく反映されるように$ apply()を手動で呼び出す必要があります。
例を見てみましょう。参加して、ページが読み込まれると、2秒後にメッセージを表示するページがあります。あなたの実装は次のようになるかもしれません:
HTML:
<body ng-app = "myApp"> <div ng-controller = "messagecontroller">遅延メッセージ:{{message}} </div> </body>JavaScript:
/ * $ apply() */ angular.module( 'myApp'、[])。コントローラー( 'messageController'、function($ scope){$ scope.getMessage = function(){setimeout(){$ scope.message = 'feeted after 3秒後';コンソール( '+$ sc. } $ scope.getMessage();この例を実行すると、2秒後にコンソールが更新されたモデルを表示していることがわかりますが、ビューは更新されていません。たぶん、あなたはすでに理由を知っているかもしれません。つまり、$ apply()メソッドを呼び出すのを忘れていました。したがって、次のようにgetMessage()を変更する必要があります。
/ * $ applyで起こること */angular.module( 'myApp'、[])。コントローラー( 'mesagecontroller'、function($ scope){$ scope.getmessage = function(){$ scope(){$ scope(){$ scope()$ apply(function(){// lapped(// $ scope.message);上記の例を実行すると、ビューも2秒後に更新されることがわかります。唯一の変更は、コードが$ scope。$ apply()にラップされるようになることです。これにより、$ rootscope。$ digest()が自動的にトリガーされるため、ウォッチャーがビューを更新するようにトリガーされます。
注:ちなみに、前者は$ apply()を呼び出すため、setimeout()の代わりに$タイムアウトサービスを使用する必要があるため、手動で呼び出す必要はありません。
また、上記のコードでは、次のように、モデルを変更した後にパラメーターなしで$ apply()を手動で呼び出すこともできます。
$ scope.getMessage = function(){settimeout(function(){$ scope.message = 'fetted feeted abed'; console.log( 'message:' + $ scope.message); $ scope。$ apply(); };上記のコードは、$ apply()の2番目のフォーム、つまりパラメーターのないフォームを使用します。パラメーターとして関数を取る$ apply()メソッドを常に使用する必要があることを覚えておくことが重要です。これは、関数を$ apply()に渡すと、関数がtry ...キャッチブロックにラップされるため、例外が発生すると、$ ExceptionHandlerサービスによって例外が処理されるためです。
$ apply()を使用する状況は次のとおりです。
•通常、ビューで使用できるAngularが提供する指令に基づいて、$ Apply()を呼び出すことができます。すべてのng- [event]ディレクティブ(ng-click、ng-keypressなど)は$ apply()を呼び出します。
•さらに、$ Digest()を呼び出すために、一連の角張った組み込みサービスに頼ることもできます。たとえば、XHRリクエストが完了し、更新戻り値がトリガーされた後、$ httpサービスは$ apply()を呼び出します。
•イベントを手動で処理するときはいつでも、サードパーティフレームワーク(jQuery、Facebook APIなど)を使用するか、settimeout()を呼び出します。$ apply()関数を使用して、Angular Return a $ digestループを作成できます。
settimeout()に電話してください:
<!doctype html> <html ng-app = "myapp"> <head> <title> $scope。$ apply()usage </title> <meta charset = "utf-8"> <スクリプトsrc = "http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"> </script> </head> <body> <body> <div> "div1" ng-controller = "mytext"> <div> {{{{{{{{{{{{{{{{{{{btn "Type =" btn "" btn "" Type value = "jQuery-event"> </input> </div> </body> </html> <script type = "text/javascript"> var mymodule = angular.module( 'myApp'、[]); mymodule.controller( "myText"、function($ scope){$ scope.text = "place"; setimeout(function(){$ scope.text = "setted edted time out"; $ scope。$ apply(); //ダーティ値の検出は手動で実行する必要があります。 </script>サードパーティのフレームワークを使用します(jquery、facebook apiなど):
<!doctype html> <html ng-app = "myapp"> <head> <title> $ scope。$ scope。$ apply()usage </title> <meta charset = "utf-8"> <script src = "https://cdn.jsdelivr.net/jquery/3.1.0/jquery.min.js"> src = "http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"> </script> <body> <body> <div id = "div1" ng-controller = "mytext"> <div> {{{{{{{{text}} value = "jQuery-event"> </input> </div> </body> </html> <script type = "text/javascript"> var mymodule = angular.module( 'myApp'、[]); mymodule.controller( "mytext"、function($ scope){$ scope.text = "place";}); $(function(){$( "#btn")。クリック(function(){var $ scope = $( "#btn")。scope(); $ scope.text = "jqueryで設定された値"; $ scope。$ apply();})</scrip>1.3。 $ DIGESTループは何回実行されますか?
$ダイジェストループが実行されているとき、ウォッチャーが実行され、スコープ内のモデルが変更されたかどうかを確認します。変更が発生した場合、対応するリスナー関数が実行されます。これには重要な問題が含まれます。リスナー機能自体がスコープモデルを変更した場合はどうなりますか? Angularjsはこの状況をどのように処理しますか?
答えは、$ダイジェストループは一度だけ実行されないということです。現在のループが終了すると、モデルが変更されたかどうかを確認するために別のループを実行します。これは汚いチェックです。これは、リスナー機能が実行されたときに発生する可能性のあるモデルの変更を処理するために使用されます。したがって、モデルが変更されなくなるか、$ Digestループが10回到達するまで、$ Digestループは実行され続けます。したがって、リスナー関数のモデルを可能な限り変更しないようにしてください。
注:リスナー関数にモデルが変更されていなくても、$ DIGESTループも少なくとも2回実行されます。上記で説明したように、モデルが変わらないようにもう一度実行されます。
結論
覚えておくべき最も重要なことは、AngularJがモデルの変更を検出できるかどうかです。検出できない場合は、手動で$ apply()を呼び出す必要があります。
ご質問がある場合は、メッセージを残してください。編集者は、すべての人に時間内に返信します。 wulin.comのウェブサイトへのご支援ありがとうございます!