序文フロントエンド開発に携わる人にとって、最も人気のあるフロントエンドフレームワークは間違いなくReactとVueです。この2つのフレームワークは誰もがよく知っていると思います。ただし、これら 2 つのフレームワークはいずれも従来の DOM テクノロジの使用を放棄し、仮想 DOM とも呼ばれる JS ベースの仮想 DOM テクノロジを採用しています。では、仮想 DOM とは何でしょうか? 2 つの一般的なフレームワークの両方が仮想 DOM を使用する理由は何ですか?次に、フロントエンド開発者の私が、DOM DIFF アルゴリズムの素晴らしさについて説明します。 仮想 DOM とは何ですか?Virtual DOM は、その名の通り仮想的な DOM です。Javascript を使用して DOM 構造をシミュレートし、JS レイヤーで DOM の変化を比較する機能が特徴です。具体的な操作は以下のとおりです。 // 通常の HTML DOM 構造 <ul class="list"> <li class="item">わい</li> <li class="item">易陽千熙</li> </ul> // マッピングされた仮想DOM { タグ:'ul', 小道具:{ クラス:'リスト' }, 子供たち: [ { タグ:'li', 小道具:{ クラス:'アイテム' }, 子供達: ['易楊千熙'] } ] } ちょっと戸惑う人もいるかもしれません。普通の HTML DOM 構造はダメなんじゃないの?理解しやすく、コードも簡潔になります。ネストされた再帰仮想 DOM を使用する必要があるのはなぜでしょうか?実は、これは通常の DOM が再レンダリングの過程で多くのパフォーマンスを消費するという事実に関係しています。DOM 操作は単純に見えますが、実際には効率はかなり低いです。これは、頻繁に変更する必要があるのが実際の DOM の場合、より複雑に見え、JS 構造を使用する仮想 DOM の方が効率的になるためです。 仮想DOMを使用する理由DOMレンダリングページ操作プロセス
同じ。 CSS ドキュメントでは、すべての要素はノードであり、HTML のタグに 1 対 1 で対応し、以下に示すように CSSOM ツリーを形成します。 警告します! DOM ツリーの構築中に JS 関連のコンテンツに遭遇すると、DOM ツリーの構築は直ちに停止します。これは、JS が DOM ノード上で操作できるためです。完成した DOM に JS が影響しないように、ブラウザは DOM ツリーの構築を防止してリソースを節約します。 DOM ツリーと CSSOM ツリーが継続的に構築されるにつれて、レンダリング ツリーも徐々に形成されます。ブラウザーは、構築されたレンダリング ツリーに基づいて Web ページのレイアウトと描画処理を実行し、Web ページを継続的に構築します。具体的な操作フローチャートは以下のとおりです。 一般的に、ページ レンダリングの日常的な操作では、DOM を操作し、innerHTML を変更してリセットすることで、ページ レンダリングを完了します。DOM 更新操作を実行するたびに、レンダリング プロセスが再度実行され、このプロセスにはページの再描画と再配置が含まれます。 仮想DOMの利点しかし、大規模なページ プロジェクトや、タグや属性が多数ある Web ページの場合、従来の DOM 操作では時間がかかりすぎます。単純な変更を行うたびに、多数の DOM ノードの再描画と再配置が必要になり、ページ レンダリングの効率が大幅に低下します。そのため、フロントエンド開発者が DOM のボトルネックに直面して途方に暮れている場合、仮想 DOM は軽量の JavaScript オブジェクトとして大きな優位性を発揮し、フロントエンド開発者の支持を獲得することに成功しています。 ページが再レンダリングされると、Virtual DOM は DOM の diff 計算と比較を 2 回実行し、差異を見つけます。DOM ツリーの異なる部分を変更するだけで済みます。Virtual DOM はミドルウェアであるとも言えます。まず、JS を使用して Virtual DOM を変更します。差異を比較した後、すべての変更がページの実際の DOM に追加されます。したがって、Virtual DOM の最大の利点は、ネイティブ DOM のように比較後に DOM を再構築して作成する必要がないことです。これは、大規模なプロジェクトの操作に非常にパフォーマンスを消費し、コストがかかるためです。Web ページのサイズに関係なく、従来の DOM を放棄して Virtual DOM を採用することは、間違いなく非常に効率的で優れた選択であることがわかります。 仮想DOMでDOMを表現する方法まず、vscodeで新しいdom diffプロジェクトを作成し、プロジェクトを初期化し、対応するコンポーネントをインストールします。 DOM ツリーなので、HTML を DOM ツリーに変換する際には再帰形式を使います。まずノードを作成し、次に属性を設定し、最後に子ノードを設定します。 <ul class="リスト"> <li class="item">わい</li> <li class="item">易陽千熙</li> </ul> // DOMツリー式変換フォーム let virtualDOM = createElement('ul', { クラス:'リスト', }, [ 要素を作成します('li',{ クラス:'アイテム' },['wjy']), 要素を作成します('li',{ クラス:'アイテム' },['易楊千熙']), ]) 次に、新しいelement.jsファイルを作成して外部に出力し、ページのレンダリングを完了します。 // ElementコンストラクタクラスElementを通じて仮想DOMノードを構築します。 コンストラクタ(型、プロパティ、子){ this.type = タイプ; プロパティ this.children =子供; } } // const createElement = (型、プロパティ、子) => { 新しい要素(type,props,children)を返します。 } // ページをレンダリングし、仮想DOMを実際のDOMに変換します const レンダリング = (domObj) => { el = document.createElement(domObj.type); とします。 for(let key in domObj.props){ setAttr(el,key,domObj.props[key]); } domObj.children.forEach(child => { child = (要素の子インスタンス) ? レンダリング(子) : document.createTextNode(子); el.appendChild(子); }) el を返します。 } 関数setAttr(ノード、キー、値){ スイッチ(キー){ ケース '値': if(node.tagName.toLowerCase() === '入力' || node.tagName.toLowerCase() === 'テキストエリア' ){ ノードの値 = 値; }それ以外{ node.setAttribute(キー、値) } 壊す; ケース 'スタイル': // node.setAttribute('style',値) node.style.cssText の値; 壊す; デフォルト: node.setAttribute(キー、値) 壊す; } } // 実際のDOMを指定されたルートノードにマウントします。const renderDOM = (el,target) => { ターゲットに子要素を追加します。 } //外部にエクスポート 要素を作成、 与える、 レンダリングDOM } コンソールで実際のDOMを取得する ページのレンダリングに成功しました! 😃 DOM DIFFアルゴリズムユーザーがインタラクティブなページ操作を変更すると、仮想 DOM ツリー上のノードは変更されますが、この時点では実際のノードは変更されません。変更を実際のページと同期させるために、DOM DIFF アルゴリズムを使用して 2 つのツリーの差異を検出し、差異パッチ オブジェクトを生成してから、差異パッチ オブジェクトを実際の DOM ノードに適用して、ページのレンダリングと更新を完了します。 従来の Diff アルゴリズムの時間計算量は O(n^3) に達します。ページ全体を毎回更新するという目的を達成するには、この指数関数的に増大するパフォーマンス オーバーヘッドではパフォーマンス要件を満たすことができません。そのため、Facebook のエンジニアはこれを最適化し、diff 戦略を策定して Diff アルゴリズムの計算量を O(n) に削減しました。 異なる戦略
差分粒度DIFF の粒度が異なるため、DIFF アルゴリズムは次の順序で実行されます。
パッチ適用React diff の diff 戦略と比較アルゴリズムに従って、深さ優先トラバーサルを通じて 2 つの仮想 DOM を比較します。違いがある場合は、トラバースされたノードのインデックス値に対応する操作 (パッチ オブジェクトとも呼ばれます) が保存されます。 次に、実際の DOM が深さ優先で再度トラバースされ、パッチ オブジェクト内のインデックスが DOM に対応し、DOM 更新操作が完了します。 結論 インターネット環境では、インタラクティブなページをいつでも更新することは、インターネットを閲覧するときに日常的に行われる操作です。ただし、この単純な操作は、複数のアルゴリズムの最適化の結果です。 DOM DIFF の基本的な原理は非常に複雑です。ご興味があれば、関連する文献をご自身で検索してください。この記事は表面的な分析に過ぎないため、あまり多くの側面については詳しく説明しません。この記事に誤りや抜けがある場合は、ご訂正ください。あらゆる合理的な批判を謙虚に受け入れましょう! 😉 この記事が DOM diff アルゴリズムの理解に役立った場合は、ぜひ高評価をお願いします。私はフロントエンド開発の初心者です。高評価をいただくたびに、前進するモチベーションになります。Nuggets のブログは今後も更新していきます。 上記は、React アプリケーションにおける DOM DIFF アルゴリズムの詳細な説明です。React アプリケーションにおける DOM DIFF アルゴリズムの詳細については、123WORDPRESS.COM の他の関連記事に注目してください。 以下もご興味があるかもしれません:
|
<<: Docker を使用して ELK ログ システムを構築する例
>>: MySQL 5.7.15 のインストールと設定方法のグラフィック チュートリアル (Windows)
最近、仕事中に問題が発生しました。Docker コンテナがホストの redis にアクセスできず、t...
データ ボリューム コンテナーは、データ ボリュームをマウントするために特別に使用されるコンテナーで...
目次1. シナリオ2. 解決策3. 結論4. 参考文献1. シナリオ日常の開発およびテスト作業には ...
最近 redis を使っていて、とても便利だと感じているのですが、インメモリ データベースを選択する...
主に低バージョンのブラウザ向け<!-- --> は HTML コメント タグです。上位バ...
1.v-bind(略称:)コンポーネント プロパティのデータで定義されたデータ変数を使用するか、コン...
ストアドプロシージャとは簡単に言えば、これは強力で、JAVA 言語のメソッドに似た比較的複雑な論理関...
背景Alibaba Cloud RDS for MySQL(MySQL バージョン 5.7)データベ...
MySQL 8.0.18 安定版 (GA) が昨日正式にリリースされ、Hash Join も期待通り...
1 セミコロン「;」のない CSS スタイル2 タグが閉じられておらず、「>」がありません...
1. mysqlbackup の紹介mysqlbackup は、MySQL Enterprise B...
まず、mysqlサービスを開始および停止します ネットストップmysql ネットスタートMySQL ...
Navicat が MySql サーバーにリモート接続できない問題の解決策は、先頭に書かれています:...
1. 何ですか視差スクロールとは、複数の背景レイヤーを異なる速度で動かすことで、3次元のモーション...
序文最近、職場でこの要件に遭遇し、リモート接続を確立するのに 1 時間以上かかりました。ローカル コ...