React仮想DOMの使い方

php中世界最好的语言
php中世界最好的语言オリジナル
2018-05-31 14:22:112005ブラウズ

今回はReact仮想DOMの使い方と、React仮想DOMを使用する際の注意点を紹介します。実際の事例を見てみましょう。

Web開発では、データの変更をリアルタイムにUIに反映させる必要がありますが、その際にDOMの操作が複雑で頻繁に行われることがパフォーマンスのボトルネックとなることが多いです。仮想 DOM (Virtual DOM) メカニズムを導入します。

1. 仮想 DOM とは何ですか?

React では、レンダリングの実行結果は実際の DOM ノードではなく、仮想 DOM と呼ばれる軽量の JavaScript オブジェクト になります。

仮想 DOM は、バッチ処理と効率的な Diff アルゴリズムを備えた React のハイライトです。これにより、パフォーマンスの問題を気にすることなく、いつでもページ全体を「更新」することができ、仮想 DOM により、インターフェイスの実際に変更された部分に対してのみ実際の DOM 操作が実行されることが保証されます。実際の開発では、基本的に仮想DOMの動作を気にする必要はありませんが、その動作メカニズムを理解することは、Reactコンポーネントのライフサイクルをより深く理解するのに役立つだけでなく、さらなる最適化にも大いに役立ちます。反応プログラム。

2. 仮想 DOM VS 直接操作するネイティブ DOM?

仮想 DOM がない場合は、innerHTML を直接リセットしてください。この操作は、大きなリスト内のすべてのデータが変更された場合には合理的ですが、データが 1 行だけ変更された場合には、innerHTML 全体もリセットする必要があり、明らかに無駄が多くなります。

innerHTML と仮想 DOM の再描画プロセスを次のように比較します。

innerHTML: HTML 文字列のレンダリング + すべての DOM 要素の再作成

仮想 DOM: 仮想 DOM のレンダリング + diff + 必要な DOM 更新

DOM 操作と比較すると、js の計算はとても安い。仮想 DOM レンダリング + diff は、HTML 文字列のレンダリングよりも明らかに遅いですが、それでも純粋な JS レベルの計算であり、後続の DOM 操作よりもはるかに安価です。もちろん、誰かが検証を行っており、React のパフォーマンスは実際の DOM を直接操作するほど良くないと言っています。 コードは次のとおりです。

function Raw() {
  var data = _buildData(),
    html = "";
  ...
  for(var i=0; i<data.length; i++) {
    var render = template;
    render = render.replace("{{className}}", "");
    render = render.replace("{{label}}", data[i].label);
    html += render;
  }
  ...
  container.innerHTML = html;
  ...
}

このテスト ケースでは、1000 個のタグを含む String が構築されて追加されています。 DOM ツリーでは、DOM 操作が実行されただけです。ただし、実際の開発プロセスでは、これらの 1,000 個の要素の更新が 20 個の論理ブロックに分散される可能性があり、各論理ブロックには 50 個の要素が含まれており、ページを更新する必要がある場合、上記のコードはおよそ DOM ツリーを更新します。以下のような形式になります:

function Raw() {
  var data = _buildData(), 
    html = ""; 
  ... 
  for(var i=0; i<data.length; i++) { 
    var render = template; 
    render = render.replace("{{className}}", ""); 
    render = render.replace("{{label}}", data[i].label); 
    html += render; 
    if(!(i % 50)) {
      container.innerHTML = html;
    }
  } 
  ... 
}

こうしてみると、ReactのパフォーマンスはネイティブDOM操作よりもはるかに優れています。

さらに、DOM は Javascript にはまったく属していません (JavaScript エンジンにも存在しません)。 Javascript は実際には非常に独立したエンジンです。DOM は実際には、JavaScript が HTML ドキュメント を操作できるようにするブラウザーによって導入された API のセットです。ジャストインタイム コンパイルの時代では、DOM を呼び出すオーバーヘッドが非常に高くなります。 Virtual DOM の実行は完全に Javascript エンジン内で行われ、そのようなオーバーヘッドはまったくありません。

React.js は、主に仮想 DOM のバッチ処理と diff により、ネイティブ DOM を直接操作するよりもパフォーマンスに大きな利点があります。バッチ処理では、すべての DOM 操作が収集され、実際の DOM に一度に送信されます。 diff アルゴリズムの時間計算量も、標準 Diff アルゴリズムの O(n^3) から O(n) に削減されました。これについては次のブログ投稿に譲ります。

3. 仮想 DOM 対 MVVM?

React と比較すると、Angular、Knockout、Vue、Avalon などの他の MVVM フレームワークはすべて データ バインディング を使用します。ディレクティブ/バインディング オブジェクトを通じて、データの変更を監視し、データが変更されたときに実際の DOM 要素への参照を保持します。変化します。 MVVM の変更チェックはデータ レベルで行われますが、React のチェックは DOM 構造レベルで行われます。 MVVM のパフォーマンスは、変更検出の実装原理によっても異なります。Angular のダーティ チェックでは、あらゆる変更の固定コストが O (ウォッチャー カウント) になります。Knockout/Vue/Avalon はすべて、js レベルと DOM レベルの両方で依存関係の収集を使用します。はい O(変更):

  1. ダーティチェック: スコープダイジェスト + 必要な DOM 更新

  2. 依存関係の収集: 依存関係を再収集 + 必要な DOM 更新

Angular の最も非効率な部分は、小さな変更でもウォッチャーの数に関連したパフォーマンス コストが発生することです。しかし!すべてのデータが変更されても、Angular は実際には影響を受けません。依存関係の収集では、初期化やデータ変更時に依存関係を再収集する必要がありますが、このコストは、少量の更新が行われる場合にはほとんど無視できますが、データ量が多い場合には一定の消費が発生します。

MVVM がリストをレンダリングするとき、各行には独自のデータ スコープがあるため、通常、各行には対応する ViewModel インスタンス、またはプロトタイプの継承を使用する少し軽い「スコープ」オブジェクトがありますが、代償もあります。したがって、ViewModel / スコープ インスタンスの作成は Virtual DOM よりもはるかに高価であるため、MVVM リスト レンダリングの初期化は React よりも遅くなることがほぼ保証されています。ここでのすべての MVVM 実装に共通する問題は、リスト レンダリングのデータ ソースが変更された場合、特にデータが新しいオブジェクトである場合に、作成済みの ViewModel インスタンスと DOM 要素を効果的に再利用する方法です。再利用の最適化を行わないと、データは「新しい」ため、MVVM は実際に以前のすべてのインスタンスを破棄し、すべてのインスタンスを再作成し、最後に再度レンダリングする必要があります。タイトルにリンクされている angular/knockout 実装が比較的遅いのはこのためです。それに対して、Reactの変更チェックはDOM構造レベルで行われるため、たとえ真新しいデータであっても、最終的な描画結果が変わっていなければ無駄な作業をする必要がありません。

Angular と Vue はどちらもリスト再描画のための最適化メカニズムを提供し、インスタンスと DOM 要素を効果的に再利用する方法をフレームワークに「ヒント」します。たとえば、データベース内の同じオブジェクトは、2 つのフロントエンド API 呼び出しでは異なるオブジェクトになりますが、同じ uid を持ちます。この時点で、uid による追跡をプロンプトして、2 つのオブジェクトが実際には同じデータであることを Angular に知らせることができます。そうすれば、元のデータに対応するインスタンスと DOM 要素を再利用でき、変更された部分のみを更新する必要があります。または、$index で直接追跡して、配列内の位置に基づいて直接再利用する「インプレース再利用」を実行することもできます。質問に示された例では、Angular 実装が $index によってトラックを追加した場合、その後の再描画は React よりもそれほど遅くなりません。 dbmonster テストでも、$index: dbmon による track を使用した後、Angular と Vue は React よりも高速です (Angular のデフォルト バージョンは最適化されていないことに注意してください。最適化されたバージョンは以下にあります)

パフォーマンスを比較するときは、初期バージョンと初期バージョンを区別する必要があります。レンダリングには、少量のデータ更新、大量のデータ更新などさまざまな機会があります。仮想 DOM、ダーティ チェック MVVM、データ収集 MVVM は、状況に応じてパフォーマンスや最適化要件が異なります。小規模なデータ更新のパフォーマンスを向上させるために、Virtual DOM には shouldComponentUpdate や不変データなどの対象を絞った最適化も必要です。

  1. 初期レンダリング: 仮想 DOM > ダーティ チェック >= 依存関係収集

  2. 小規模データ更新: 仮想 DOM + 最適化 > 仮想 DOM なし最適化

  3. 大規模なデータ更新: ダーティ チェック + 最適化>= 依存関係の収集 + 最適化> 仮想 DOM (最適化できない/不要)>> MVVM は最適化なし

  4. (この段落は、 Zhihu 回答)

  5. 4. React 仮想 DOM についての誤解はありますか?

    React は、「React はネイティブ DOM 操作よりも速い」とは決して言っていません。 React は、手動による最適化を行わなくても、適切なパフォーマンスを提供できることを保証します。

    React は基礎となる DOM 操作をマスクし、より宣言的な方法で目的を記述することができるため、コードの保守が容易になります。以下は Zhihu の回答に基づいています: フレームワークの DOM 操作層は、上位層 API とその実装によって生成される可能性のある操作に対処する必要があるため、純粋な手動操作よりも速く DOM 操作を最適化できるフレームワークはありません。普遍的でなければなりません。どのベンチマークでも、どのフレームワークよりも高速な手動最適化を作成できますが、一体何が意味があるのでしょうか?実際のアプリケーションを構築する際、あらゆる箇所を手動で最適化しますか?保守性の理由から、これは明らかに不可能です。

    この記事の事例を読んだ後は、その方法を習得したと思います。さらに興味深い情報については、php 中国語 Web サイトの他の関連記事に注目してください。

    推奨読書:

    バックエンドコードを使用したWeChatミニプログラムへの写真アップロードの実装

    WeChatミニプログラムへの写真アップロードの実際のケースの分析

    以上がReact仮想DOMの使い方の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。