web-dev-qa-db-ja.com

AngularJSではデータバインディングはどのように機能しますか?

AngularJSフレームワークでデータバインディングはどのように機能しますか?

彼らのサイト で技術的な詳細を見つけることができませんでした。データがビューからモデルに伝播されたときにどのように機能するかは、ほぼ明らかです。しかし、AngularJSは、セッターやゲッターなしでモデルプロパティの変更をどのように追跡するのでしょうか。

私は JavaScriptウォッチャーがいることを発見しました これはこの仕事をするかもしれません。しかし、 Internet Explorer 6 および Internet Explorer 7 ではサポートされていません。では、AngularJSは、たとえば次のように変更したことをどのようにしてビューに反映したのでしょうか。

myobject.myproperty="new value";
1878
Pashec

AngularJSは値を記憶し、それを以前の値と比較します。これは基本的なダーティーチェックです。値が変化した場合は、changeイベントが発生します。

$apply()メソッドは、非AngularJSの世界からAngularJSの世界に移行するときに呼び出すもので、$digest()を呼び出します。ダイジェストは単なる古いダーティチェックです。すべてのブラウザで動作し、完全に予測可能です。

ダーティーチェック(AngularJS)とチェンジリスナー( KnockoutJS および Backbone.js )を対比すると、ダーティーチェックは単純に見え、非効率的でさえあるかもしれませんが(後で説明します)。それは常に意味論的に正しいですが、変更リスナーは奇妙なコーナーケースをたくさん持っていて、それをより意味論的に正しいものにするために依存関係追跡のようなものが必要です。 KnockoutJS依存関係追跡は、AngularJSにはない問題に対する賢い機能です。

変更リスナーに関する問題

  • ブラウザはネイティブにサポートしていないため、構文は厄介です。はい、プロキシはありますが、すべての場合において意味的に正しいわけではありません。もちろん、古いブラウザにはプロキシはありません。要するに、ダーティーチェックでは _ pojo _ を実行できますが、KnockoutJSとBackbone.jsではクラスから継承し、アクセサを介してデータにアクセスする必要があります。
  • 合体を変える。項目の配列があるとします。追加するためにループしているときに、項目を配列に追加するとします。追加するたびに、変更時にイベントが発生し、UIがレンダリングされます。これはパフォーマンスにとって非常に悪いです。あなたが欲しいのは、最後に一度だけUIを更新することです。変更イベントはきめ細かいです。
  • 変更リスナーはセッターですぐに起動しますが、これは問題です。変更リスナーはさらにデータを変更できるため、より多くの変更イベントが起動されるためです。スタック上では、一度に複数の変更イベントが発生する可能性があるため、これは良くありません。何らかの理由で同期をとる必要がある2つの配列があるとします。どちらか一方にしか追加できませんが、追加するたびに変更イベントが起動されます。変更イベントには現在、矛盾した世界観があります。これは、各コールバックが排他的に実行されるため、JavaScriptが回避するスレッドロックと非常によく似た問題です。変更イベントはこれを壊します。セッターは意図的ではなく明白ではない広範囲にわたる結果をもたらす可能性があるため、スレッドの問題が再び発生するためです。リスナーの実行を遅らせ、一度に1つのリスナーのみが実行されることを保証することが必要です。したがって、どのコードでも自由にデータを変更できます。その間、他のコードは実行されません。 。

パフォーマンスはどうですか?

したがって、ダーティーチェックは非効率的であるため、遅くなっているように見えます。これが、理論的な議論ではなく実数を調べる必要があるところですが、最初にいくつかの制約を定義しましょう。

人間は:

  • 遅い - 50ミリ秒より速いものは人間には知覚できないため、「インスタント」と見なすことができます。

  • 限られた - あなたは本当に1ページで人間に約2000個以上の情報を見せることはできません。それ以上のものは本当に悪いUIであり、人間はとにかくこれを処理することができません。

それで本当の質問はこれです:あなたは50ミリ秒の間にどれぐらいの比較をあなたがブラウザですることができますか?これは多くの要因が関係してくるので答えるのは難しい質問ですが、これはテストケースです: http://jsperf.com/angularjs-digest/6 これは10,000人のウォッチャーを作成します。最近のブラウザでは、これは6ミリ秒弱かかります。 On Internet Explorer 8 約40 msかかります。ご覧のとおり、最近の遅いブラウザでもこれは問題になりません。警告があります:比較は制限時間に収まるように簡単である必要があります...残念ながらAngularJSに遅い比較を追加するのは非常に簡単なので、あなたが何を知らないか遅いアプリケーションを構築するのは簡単です。やっている。しかし、私たちはインストルメンテーションモジュールを提供することによって答えを得たいと思っています。

ビデオゲームとGPUがダーティチェックアプローチを使用していることがわかります。これは特に一貫性があるためです。モニタのリフレッシュレート(通常は50〜60 Hz、または16.6〜20 msごと)を超える限り、それ以上のパフォーマンスは無駄になります。そのため、FPSを高くするよりも、より多くのものを描画することをお勧めします。

2711
Misko Hevery

Miskoは既にデータバインディングの仕組みについて優れた説明を行っていますが、データバインディングのパフォーマンスの問題に関する見解を追加したいと思います。

Miskoが述べたように、2000前後のバインディングで問題が発生し始めますが、とにかく1ページに2000以上の情報を含めるべきではありません。これは本当かもしれませんが、すべてのデータバインディングがユーザーに表示されるわけではありません。双方向バインディングを使用して何らかのウィジェットまたはデータグリッドの構築を開始すると、悪いUXがなくても、2000バインディングを簡単にヒットできます。

たとえば、使用可能なオプションをフィルタリングするためにテキストを入力できるコンボボックスを検討してください。この種のコントロールには、〜150個のアイテムを含めることができ、それでも非常に使いやすくなります。追加の機能(現在選択されているオプションの特定のクラスなど)がある場合は、オプションごとに3〜5個のバインディングを取得し始めます。これらのウィジェットのうち3つをページに配置し(たとえば、1つは国を選択し、もう1つはその国の都市を選択し、3つ目はホテルを選択します)、あなたは既に1000から2000のバインディングのどこかにいます。

または、企業Webアプリケーションのデータグリッドを検討してください。 1ページあたり50行は無理ではありません。各行には10〜20列を含めることができます。 ng-repeatsでこれを構築する場合、および/またはいくつかのバインディングを使用するいくつかのセルに情報がある場合、このグリッドだけで2000個のバインディングに近づくことができます。

これはAngularJSで作業するときにhugeの問題であり、これまで見つけた唯一の解決策は、ngOnceを使用する代わりに、双方向バインディングを使用せずにウィジェットを構築することですウォッチャーと同様のトリック、またはjQueryとDOM操作でDOMを構築するディレクティブを作成します。そもそもAngularを使用する目的に反すると感じます。

これを処理する他の方法についての提案を聞きたいと思いますが、それから私は自分の質問を書く必要があります。これをコメントに入れたかったのですが、そのためには長すぎます...

TL; DR
データバインディングは、複雑なページでパフォーマンスの問題を引き起こす可能性があります。

318
MW.

$scopeオブジェクトをダーティーチェックすることによって

Angularは$scopeオブジェクト内にウォッチャーの単純なarrayを維持します。 $scopeを調べると、$$watchersというarrayが含まれていることがわかります。

各ウォッチャーは、とりわけobjectであり、

  1. ウォッチャーが監視している表現。これは単にattributeの名前、あるいはもっと複雑な名前かもしれません。
  2. 式の最後の既知の値。これは、式の現在の計算値と照らし合わせて確認できます。値が異なる場合、ウォッチャーは関数を起動して$scopeをダーティとしてマークします。
  3. ウォッチャーが汚れている場合に実行される関数。

ウォッチャーの定義方法

AngularJSでウォッチャーを定義するには、さまざまな方法があります。

  • $watchに明示的に$scopeおよびattributeを付けることができます。

    $scope.$watch('person.username', validateUnique);
    
  • あなたのテンプレートに{{}}補間を置くことができます(現在の$scope上にウォッチャーが作成されます)。

    <p>username: {{person.username}}</p>
    
  • ウォッチャーを定義するためにng-modelなどのディレクティブを要求することができます。

    <input ng-model="person.username" />
    

$digestサイクルはすべてのウォッチャーを最後の値と比較します

通常のチャンネル(ng-model、ng-repeatなど)を通してAngularJSと対話するとき、ダイジェストサイクルはディレクティブによって引き起こされます。

ダイジェストサイクルは$scopeとそのすべての子の深さ優先のトラバースです。 $scopeobjectごとに、その$$watchersarrayを繰り返し処理し、すべての式を評価します。新しい式の値が最後の既知の値と異なる場合は、ウォッチャーの関数が呼び出されます。この関数はDOMの一部を再コンパイルし、$scopeの値を再計算し、AJAXrequestをトリガーします。

すべてのスコープがトラバースされ、すべての監視式が最後の値に対して評価およびチェックされます。

ウォッチャーがトリガーされた場合、$scopeは汚れています

ウォッチャーがトリガーされると、アプリは何かが変更されたことを認識し、$scopeはダーティとしてマークされます。

ウォッチャー関数は$scope上または親$scope上の他の属性を変更することができます。 1つの$watcher関数がトリガされた場合、他の$scopeがまだクリーンであることを保証することはできないため、ダイジェストサイクル全体をもう一度実行します。

これは、AngularJSには双方向のバインディングがあるため、データを$scopeツリーに戻すことができるためです。すでにダイジェストされているより高い$scopeの値を変更することがあります。おそらく$rootScopeの値を変更します。

$digestが汚れている場合は、$digestサイクル全体をもう一度実行します。

ダイジェストサイクルがクリーンになるまで(すべての$digest式が前のサイクルと同じ値になるまで)、またはダイジェスト制限に達するまで、$watchサイクルを繰り返します。デフォルトでは、この制限は10に設定されています。

ダイジェスト制限に達すると、AngularJSはコンソールにエラーを表示します。

10 $digest() iterations reached. Aborting!

ダイジェストはマシン上では困難ですが開発者にとっては簡単です

ご覧のとおり、AngularJSアプリケーションで何かが変更されるたびに、AngularJSは$scope階層内のすべてのウォッチャーをチェックして応答方法を確認します。開発者にとってこれは大規模な生産性の恩恵です。配線コードをほとんど記述する必要がなくなるため、AngularJSは値が変更されたかどうかを確認し、それ以外の部分は変更と一致するようにします。

マシンの観点から見ると、これは非常に非効率的であり、作成するウォッチャーが多すぎるとアプリの動作が遅くなります。 Miskoは、古いブラウザではアプリの動作が遅くなる前に、約4000人のウォッチャーの数を引用しました。

たとえば、大きなJSONarrayの上にng-repeatを付けた場合、この制限に達するのは簡単です。ウォッチャーを作成せずにテンプレートをコンパイルするためのワンタイムバインディングなどの機能を使用して、これを軽減できます。

あまりにも多くのウォッチャーを作成しないようにする方法

ユーザーがアプリと対話するたびに、アプリ内のウォッチャーは少なくとも1回は評価されます。 AngularJSアプリを最適化することの大きな部分は、あなたの$scopeツリー内のウォッチャーの数を減らすことです。これを行う簡単な方法の1つは、 ワンタイムバインディング を使用することです。

めったに変更されないデータがある場合は、::構文を使用して1回しかバインドできません。

<p>{{::person.username}}</p>

または

<p ng-bind="::person.username"></p>

バインディングは、それを含むテンプレートがレンダリングされ、データが$scopeにロードされたときにのみトリガーされます。

あなたがng-repeatにたくさんのアイテムを持っているとき、これは特に重要です。

<div ng-repeat="person in people track by username">
  {{::person.username}}
</div>
151
superluminary

これが私の基本的な理解です。それは間違っているかもしれません!

  1. アイテムは$watchメソッドに関数を渡すことで監視されます(監視対象のものを返します)。
  2. 監視項目への変更は、$applyメソッドでラップされたコードブロック内で行う必要があります。
  3. $applyの最後に$digestメソッドが呼び出され、各ウォッチを調べて、前回の$digestの実行以降に変更されたかどうかを確認します。
  4. 何らかの変更が見つかった場合は、すべての変更が安定するまでダイジェストが再度呼び出されます。

通常の開発では、HTMLのデータバインディング構文はAngularJSコンパイラにウォッチを作成するように指示し、コントローラメソッドはすでに$apply内で実行されます。そのため、アプリケーション開発者にとっては、それはすべて透明です。

79
Pete BD

私はしばらくこれを自分で思った。セッターがないと、AngularJS$scopeオブジェクトへの変更をどのように認識しますか?それは彼らを世論調査しますか?

それが実際にしていることはこれです:あなたがモデルを修正するどんな "普通の"場所も既にAngularJSの内部から呼ばれているので、あなたのコードが走った後自動的に$applyを呼び出します。あなたのコントローラが何らかの要素のng-clickにフックされているメソッドを持っているとしましょう。 AngularJSはあなたにそのメソッドの呼び出しを結びつけるので、適切な場所で$applyをする機会があります。同様に、ビューに正しく現れる式の場合、それらはAngularJSによって実行されるので、$applyが実行されます。

ドキュメントがコード_ AngularJSの外側のために手動で$applyを呼び出さなければならないことについて話しているとき、それは実行時にコールスタック内のAngularJSから生じないコードについて話しています。

61
jpsimons

写真で説明する:

データバインディングにはマッピングが必要です

スコープ内の参照は、テンプレート内の参照と正確には一致しません。 2つのオブジェクトをデータバインドするとき、最初のオブジェクトをリッスンし、もう一方のオブジェクトを変更する3番目のオブジェクトが必要です。

enter image description here

ここで、<input>を修正するときは、 data-ref3 をタッチします。そして古典的なデータバインドの仕組みは data-ref4 に変わるでしょう。では、他の{{data}}式はどのように移動するのでしょうか。

イベントは$ digest()につながります

enter image description here

AngularはすべてのバインディングのoldValuenewValueを管理します。そしてすべてのAngular eventの後に、有名な$digest()ループがWatchListをチェックして何かが変更されたかどうかを確認します。これらのAngularイベントng-clickng-change$http完了です。oldValuenewValueと異なる限り、$digest()はループします。

前の図では、data-ref1とdata-ref2が変更されています。

結論

卵と鶏のようです。誰が始めたのかは決してわかりませんが、うまくいけば期待通りに動作します。

もう1つのポイントは、メモリとCPUに対する単純なバインディングの影響を簡単に理解できるということです。うまくいけば、デスクトップはこれを処理するのに十分な太さです。携帯電話はそれほど強くはありません。

32
Nicolas Zozol

アタッチされたオブジェクトに変更があるかどうかScopeの定期的なチェックは明らかにありません。スコープにアタッチされているすべてのオブジェクトが監視されるわけではありません。スコープはプロトタイプ的に $$ウォッチャー を管理します。 Scopeは、$$watchersが呼び出されたときにのみ、この$digestを反復処理します。

Angularは、これらのそれぞれについて$$ウォッチャーにウォッチャーを追加します。

  1. {{expression}} - あなたのテンプレートの中(そして式があるところならどこにでも)、またはng-modelを定義するとき。
  2. $ scope。$ watch( 'expression/function') - あなたのJavaScriptでは見たい角度のスコープオブジェクトを追加することができます。

$ watch functionは3つのパラメータを取ります。

  1. 最初のものは単にオブジェクトを返すウォッチャー関数であるか、あるいは単に式を追加することができます。

  2. 2つ目は、オブジェクトに変更があったときに呼び出されるリスナー関数です。 DOMの変更のようなものはすべてこの関数に実装されます。

  3. 3番目はブール値を取るオプションのパラメータです。 trueの場合、angle deepはオブジェクトを監視します。falseの場合、Angularはオブジェクトを参照しているだけです。 $ watchの大まかな実装はこんな感じです

Scope.prototype.$watch = function(watchFn, listenerFn) {
   var watcher = {
       watchFn: watchFn,
       listenerFn: listenerFn || function() { },
       last: initWatchVal  // initWatchVal is typically undefined
   };
   this.$$watchers.Push(watcher); // pushing the Watcher Object to Watchers  
};

Angularには、Digest Cycleという興味深いことがあります。 $ digestサイクルは、$ scope。$ digest()への呼び出しの結果として始まります。 ng-clickディレクティブを使用してハンドラー関数内の$スコープモデルを変更するとします。その場合AngularJSは自動的に$ digest()を呼び出すことで$ digestサイクルを起動しますng-clickに加えて、モデルを変更することを可能にするいくつかの他の組み込みディレクティブ/サービスがあります(例えばng-model、$ timeoutなど)。そして自動的に$ダイジェストサイクルを引き起こします。 $ digestの大まかな実装は次のようになります。

Scope.prototype.$digest = function() {
      var dirty;
      do {
          dirty = this.$$digestOnce();
      } while (dirty);
}
Scope.prototype.$$digestOnce = function() {
   var self = this;
   var newValue, oldValue, dirty;
   _.forEach(this.$$watchers, function(watcher) {
          newValue = watcher.watchFn(self);
          oldValue = watcher.last;   // It just remembers the last value for dirty checking
          if (newValue !== oldValue) { //Dirty checking of References 
   // For Deep checking the object , code of Value     
   // based checking of Object should be implemented here
             watcher.last = newValue;
             watcher.listenerFn(newValue,
                  (oldValue === initWatchVal ? newValue : oldValue),
                   self);
          dirty = true;
          }
     });
   return dirty;
 };

JavaScriptの setTimeout() 関数を使用してスコープモデルを更新した場合、Angularを使用して変更内容を知ることはできません。この場合、$ apply()を手動で呼び出すことが私たちの責任です。これは$ダイジェストサイクルを引き起こします。同様に、DOMイベントリスナを設定し、ハンドラ関数内でいくつかのモデルを変更するディレクティブがある場合は、変更を確実に有効にするために$ apply()を呼び出す必要があります。 $ applyの大きなアイデアは、Angularを意識していないコードを実行できるということです。そのコードはスコープ上のものを変更する可能性があります。そのコードを$ applyでラップすると、$ digest()を呼び出すようになります。 $ apply()の大まかな実装.

Scope.prototype.$apply = function(expr) {
       try {
         return this.$eval(expr); //Evaluating code in the context of Scope
       } finally {
         this.$digest();
       }
};
21

AngularJSは、3つの強力な関数、 $ watch()$ digest() 、および $ apply() の助けを借りて、データバインディングメカニズムを処理します。ほとんどの場合AngularJSは$ scope。$ watch()と$ scope。$ digest()を呼び出しますが、場合によってはこれらの関数を手動で呼び出して新しい値で更新する必要があります。

$ watch() : -

この関数は、$スコープ上の変数の変化を監視するために使用されます。式、リスナー、および等価オブジェクトの3つのパラメーターを受け入れます。リスナーおよび等価オブジェクトはオプションのパラメーターです。

$ digest() -

この関数は、$ scopeオブジェクトとその子の$ scopeオブジェクト内のすべてのウォッチを繰り返し処理します。
(ある場合) $ digest()がウォッチを反復処理するときに、式の値が変更されたかどうかをチェックします。値が変更されている場合、AngularJSは新しい値と古い値でリスナーを呼び出します。 AngularJSが必要と判断したときはいつでも$ digest()関数が呼び出されます。たとえば、ボタンをクリックした後やAJAXを呼び出した後などです。 AngularJSが$ digest()関数を呼び出していない場合があります。その場合はあなた自身でそれを呼ばなければなりません。

$ apply() -

Angular doはAngularJSのコンテキスト内にあるモデルの変更のみを自動的に更新します。 Angularコンテキスト以外のモデル(ブラウザのDOMイベント、setTimeout、XHR、またはサードパーティ製のライブラリなど)で変更を行った場合は、呼び出しによって変更をAngularに通知する必要があります。手動で$ apply()します。 $ apply()関数の呼び出しが終了すると、AngularJSは内部で$ digest()を呼び出します。そのため、すべてのデータバインディングが更新されます。

14
Bharath Kumar

ある人のデータモデルとフォームをリンクする必要があることが起こりました。私がしたのは、データとフォームを直接マッピングすることでした。

たとえば、モデルに次のようなものがあるとします。

$scope.model.people.name

フォームの制御入力:

<input type="text" name="namePeople" model="model.people.name">

こうすれば、オブジェクトコントローラの値を変更した場合、これは自動的にビューに反映されます。

モデルに合格した例はサーバーデータから更新されます。あなたが郵便番号に基づいて郵便番号を要求し、ロードに基づいてそのビューに関連付けられたコロニーと都市のリストをリストし、デフォルトでユーザーに最初の値を設定します。そしてこれがうまくいった、angularJSがモデルをリフレッシュするのに時々数秒かかる、それをするためにあなたはデータを表示している間スピナーを置くことができます。

6
gartox
  1. 一方向データバインディングは、値がデータモデルから取得され、HTML要素に挿入されるアプローチです。モデルをビューから更新する方法はありません。それは古典的なテンプレートシステムで使われています。これらのシステムはデータを一方向にのみバインドします。

  2. Angular appsでのデータバインディングは、モデルコンポーネントとビューコンポーネント間のデータの自動同期です。

データバインディングを使用すると、モデルをアプリケーション内の単一の真実の源として扱うことができます。ビューは常にモデルの投影です。モデルが変更されると、ビューはその変更を反映します。

5

AngularJは双方向データバインディングをサポートします。
data View - > ControllerController - > Viewにアクセスできることを意味

1)

// If $scope have some value in Controller. 
$scope.name = "Peter";

// HTML
<div> {{ name }} </div>

O/P

Peter

あなたはng-modelでデータをバインドすることができます。
2)

<input ng-model="name" />

<div> {{ name }} </div>

ここで上の例では、入力ユーザーが何を指定しても、それは<div>タグに表示されます。

HTMLからの入力をコントローラにバインドしたい場合: -
3)

<form name="myForm" ng-submit="registration()">
   <label> Name </lbel>
   <input ng-model="name" />
</form>

ここでコントローラで入力nameを使いたいのなら、

$scope.name = {};

$scope.registration = function() {
   console.log("You will get the name here ", $scope.name);
};

ng-modelはビューをバインドし、それを式{{ }}にレンダリングします。
ng-modelは、ビュー内でユーザーに表示され、ユーザーが対話するデータです。
したがって、Angular Jにデータをバインドするのは簡単です。

4
ojus kulkarni

これは、入力フィールドを使用したAngularJSによるデータバインディングの例です。後で説明します

HTMLコード

<div ng-app="myApp" ng-controller="myCtrl" class="formInput">
     <input type="text" ng-model="watchInput" Placeholder="type something"/>
     <p>{{watchInput}}</p> 
</div>

AngularJSコード

myApp = angular.module ("myApp", []);
myApp.controller("myCtrl", ["$scope", function($scope){
  //Your Controller code goes here
}]);

上の例でわかるように、 AngularJS ng-modelを使用してHTML要素、特にinputフィールドで何が起こるかを監視しています。何かが起こったら、何かをしなさい。今回の場合、ng-modelは、口ひげの表記法{{}}を使用して、ビューにバインドされています。入力フィールド内に入力された内容は即座に画面に表示されます。そしてそれが、最もシンプルな形でAngularJSを使用した、データバインディングの美しさです。

お役に立てれば。

ここで実用的な例を参照してください Codepen

4
AllJs

Angular.jsは、ビュー内で作成したすべてのモデルに対してウォッチャーを作成します。モデルが変更されるたびに、 "ng-dirty"クラスがモデルに追加されます。そのため、ウォッチャーは "ng-dirty"クラスを持つすべてのモデルを観察し、コントローラ内の値を更新します。

3

データバインディング:

データバインディングとは何ですか?

ユーザーがビュー内のデータを変更するたびに、その変更がスコープモデル内で更新されます。その逆も同様です。

どのように可能ですか?

短い答え: ダイジェストサイクルの助けを借りて。

説明: Angular jsスコープモデルにウォッチャーを設定します。モデルに変更があると、リスナー関数が起動されます。

$scope.$watch('modelVar' , function(newValue,oldValue){

//新しい値でDom更新コード

;));

では、ウォッチャ関数はいつ、どのように呼び出されますか。

ウォッチャー関数はダイジェストサイクルの一部として呼び出されます。

ダイジェストサイクルは、ng-model、ng-bind、$ timeout、ng-clickなどのディレクティブ/サービスに組み込まれたangle jsの一部として自動的にトリガーされると呼ばれます。ダイジェストサイクルをトリガーすることができます。

ダイジェストサイクル機能:

$scope.$digest() -> digest cycle against the current scope.
$scope.$apply() -> digest cycle against the parent scope 

ie$rootScope.$apply()

注:$ apply()は$ rootScopeと同じです$ digest()これは、ダーティーチェックがrootまたはtopまたは親スコープから、angle jsアプリケーション内のすべての子$スコープまでで始まることを意味します。

上記の機能は上記のバージョンのブラウザIEでも動作します。これは、アプリケーションがAngular JSアプリケーションであることを確認することによっても可能です。

ありがとうございました。

2
Dhana