1. はじめに Vue の核となるのは双方向バインディングと仮想 DOM (以下、vdom と呼びます) です。双方向バインディングについては、Xylophone の記事「Vue の原則の分析と双方向バインディング MVVM の実装」を参照してください。 Vdom はツリー構造であり、そのノードは vnode です。 Vnode はブラウザ DOM 内のノードと 1 対 1 で対応します。対応するノードには、vnode の elm 属性を通じてアクセスできます。 vdom は純粋な JS オブジェクトであるため、操作は非常に効率的ですが、vdom への変更は最終的に DOM 操作に変換されます。効率的な DOM 操作を実現するには、効率的な仮想 DOM 差分アルゴリズムが必要です。 Vue の diff アルゴリズムは snabbdom に基づいており、興味のある友人はそれをチェックすることを選択できます。 これは「React の diff アルゴリズム」の典型的な図です。 Vue の diff アルゴリズムは同じです。つまり、同じレベルの vnode 間でのみ diff が実行され、同じレベルの vnode 間で diff が再帰的に実行され、最終的に DOM ツリー全体が更新されます。同じレベルの vnode diff の詳細は何ですか?まさにこの記事ではこれについて説明します。 2. 例 この簡略化された例を使用して、以下の diff プロセスを説明します。 上記の例のように、更新前はノードリストが 1 から 10 まで並んでおり、更新後はノードリストがランダムな順序で並んでいます。図に次のタイプのノード変更をリストします。 (1)頭と尾が同じノード:1、10など (2)同じ先頭と末尾を持つノード:2と9など(同じ先頭と末尾を持つノードの処理後) (3)新たに追加されたノード:11 (4)削除されたノード:8 (5)その他のノード:3、4、5、6、7 3. シンプルな差分 単純な diff アルゴリズムは次のように設計できます。 newVdom のノードを 1 つずつ走査し、oldVdom 内での位置を見つけます。見つかった場合は、対応する DOM 要素を移動します。見つからない場合は、新しいノードが追加されたことを意味するため、新しいノードが作成され、挿入されます。トラバーサルが完了した後、oldVdom にまだ処理されていないノードがある場合は、これらのノードが newVdom で削除されていることを意味するため、削除するだけです。 よく考えてみると、ほぼすべてのステップで DOM を移動する必要があり、全体的な DOM 構造があまり変わらない場合はコストが非常に高くなります。実際のところ、DOM があまり変化しないということはよくあります。多くの場合、特定のノードのテキストを変更するだけで済みます。 次に、Vueのdiff実装を見てみましょう。 4. Vueのdiff実装 上記の例では、oldStart+oldEnd と newStart+newEnd という 2 つのポインターのペアを描画しました。これらはそれぞれ、oldVdom と newVdom の開始点と終了点に対応します。開始点と終了点の前のノードが処理対象となるノードです。 Vue は vnode の処理を継続し、開始点と終了点のペアが出会うまでポインターを移動します。 Vue は、処理されたノードを oldVdom と newVdom の両方で処理済みとしてマークします (マーク方法については後で説明します)。 Vue は以下の対策を講じることで diff のパフォーマンスを向上させます。 1. 特別なシナリオを優先する (1)先頭に同じ種類のノード、末尾に同じ種類のノード これらのノードの位置は更新の前後で変化しないため、対応するDOMを移動する必要はありません。 (2)頭と尾/尾と頭に同じ種類のノードがある このタイプのノードの場所は非常に明確なので、探すのに時間を費やす必要はなく、DOMを直接移動するだけです。 これらのシナリオを処理すると、一方では、移動する必要のない一部の DOM が迅速に処理され、他方では、処理されるノードの数が削減されるため、後続の操作の処理範囲が縮小され、パフォーマンスが向上します。 (II)「その場での再利用」 「インプレース再利用」とは、Vue が DOM を可能な限り再利用し、DOM の移動を可能な限り避けることを意味します。 Vue は、更新前と更新後にポインターが同じノードを指しているかどうかを判断するときに、実際に同じ DOM ノードを参照する必要はありません。実際には、同じタイプのノードを指しているかどうかを判断するだけです (たとえば、2 つの異なる div は DOM 上では異なりますが、同じタイプのノードに属しています)。同じタイプのノードの場合、Vue は DOM を直接再利用します。これの利点は、DOM を移動する必要がないことです。上記の例を見ると、10 個のノードすべてが div である場合、diff プロセス全体で DOM 移動操作は行われません。 「インプレース再利用」については、Vue の公式ドキュメントに記載されています。それは利益をもたらしますが、いくつかの問題も引き起こします。友達がレビューできます。 https://cn.vuejs.org/v2/guide/list.html#key 再利用可能な要素を管理するには、https://cn.vuejs.org/v2/guide/conditional.html#Use-key- を使用します。 5. ステップバイステップの解剖例 1. 全体図 まずは全体像を見てみましょう。全体の diff は 2 つの部分に分かれています。 (1)最初の部分はループです。ループ内には分岐ロジックがあります。各ループは 1 つのブランチにのみ入ります。各ループはノードを処理します。処理後、ノードは処理済みとしてマークされます (oldVdom と newVdom の両方をマークする必要があります。ノードがいずれかの vdom にのみ表示される場合は、他の vdom でマークする必要はありません)。マークする方法は2つあります。ノードが vdom のポインターに正確に位置している場合は、ポインターを移動して未処理リストから除外します。それ以外の場合は、他の方法を使用する必要があります。 Vue のアプローチは、ノードを undefined に設定することです。 (2)ループ終了後、newVdomまたはoldVdomに未処理のノードが残る場合がある。 newVdom に未処理のノードがある場合、これらのノードは新しく追加されたノードであり、処理されます。 oldVdom にそのようなノードがある場合、それらは削除する必要があるノードであり、それに応じて DOM ツリーで削除されます。 全体のプロセスは、更新前と更新後の vdom の違いを徐々に見つけ、その違いを DOM ツリー (つまり、パッチ) に反映することです。特に重要なのは、Vue のパッチはリアルタイムであり、DOM を操作するためにすべての変更をまとめてパッケージ化するわけではないということです (React は更新をキューに入れて集中的に処理します)。友達は、これはパフォーマンスが悪いのかと聞いてくるでしょう。実際、最新のブラウザではこのような DOM 操作が最適化されており、違いはありません。 (II)段階的な分析 (1)先頭の同じタイプのノードを処理する。つまり、oldStartとnewStartは同じタイプのノードを指す。例えば、次の図のノード1である。 この場合、ノード 1 の変更が DOM に更新され、マークされます。マーキング方法は、oldStart と newStart を 1 つ後ろにシフトすることです。プロセス中に DOM を移動する必要はありません (属性の変更、テキスト コンテンツの変更など、DOM の更新が必要になる場合があります)。 (2)末尾の同じタイプのノードを処理する。つまり、oldEndとnewEndが同じタイプのノードを指している場合(次の図のノード10など) この場合もケース(1)と同様に、ノード10の変更がDOMに更新され、oldEndとnewEndが1つ前へ移動してマークされます。 DOM を移動する必要もありません。 (3)先頭と末尾/末尾の先頭、つまりoldStartとnewEndで同じタイプのノードを処理する場合、およびoldEndとnewStartが同じタイプのノードを指している場合(下図のノード2と9など) まず、ノード 2 を見てみましょう。これは実際には後方に移動します。どこに移動するのでしょうか? oldEnd が指すノード (つまり、ノード 9) に移動します。移動後、ノードをマークし、oldStart を 1 つ後ろに移動し、newEnd を 1 つ前に移動します。 手術が完了すると、状況は次のようになります 同様にノード9も同じように処理され、処理後は次のようになる。 (4)新しく追加されたノードの処理 newStartはノード11の位置に到達し、ノード11はoldVdomに見つからないため、新しく追加されたことがわかります。 次に、新しいノードを作成し、それを DOM ツリーに挿入します。どこに挿入しますか?これを oldStart が指すノード (つまり、ノード 3) の前に挿入し、newStart を 1 つ戻して処理済みとしてマークします (oldVdom にはノード 11 がないため、マーク処理中にそのポインターを移動する必要はありません)。処理後は以下のようになります (5)更新されたノードの処理 ステップ(4)の後、newStartはoldVdom内で見つかるノード7に到達しますが、これはポインター位置にはなく(oldVdom内のoldStartからoldEndまでの区間のノードを検索)、その位置が移動したことを示しています。 次に、それを DOM ツリー内で移動する必要があります。どこに移動すればいいでしょうか?それを oldStart が指すノード (つまりノード 3) に移動します。同時に、ノードを処理済みとしてマークします。これはこれまでのケースとは少し異なります。 newVdom では、ノードはポインターの下にあるため、newStart を移動してマークすることができます。 oldVdomでは、ノードはポインタにないので、それをundefinedに設定してマークする方法を使用します(マークする必要があるかどうかは後で説明します) 処理後は以下のようになる (6)処理ノード3、4、5、6 ステップ(5)の処理後、満足のいくシーンが表示されます。 NewStart と oldStart は再び同じノードを指します (つまり、両方ともノード 3 を指します)。とても簡単です。 (1)の方法でポインタを移動させるだけです。とても効率的です。 3、4、5、6も同様に処理されます。処理後は以下のようになります (7)削除する処理ノード 最初の 6 つのステップ (実際には最初の 6 つのステップはループで実行されます) の後、newStart が newEnd を越えて、それらが出会うことがわかります。この時点では、oldStart と oldEnd は一致していません。つまり、これら 2 つのポインター間のノード (それらが指すノード、つまり上図のノード 7 と 8 を含む) が、この更新で削除されるノードです。 OK、それではDOMツリーからそれらを削除します。前のセクションに戻って、ノード 7 をマークしましょう。マークが必要なのはなぜでしょうか?マークの目的は、それが処理されたこと、そしてそれが新しい DOM に表示される必要があるノードであることを Vue に伝えることです。削除しないでください。ここではノード 8 のみを削除する必要があります。 アプリケーションでは、oldVdom の開始点と終了点が一致するが、newVdom の開始点と終了点が一致しない状況が発生することもあります。このとき、newVdom 内の未処理のノードを処理する必要があります。これらのノードは更新中に追加されたノードであり、DOM ツリーに挿入する必要があります。 この時点で、diffプロセス全体は終了です。 Vue の diff アルゴリズムは、動的プログラミング アルゴリズムの「a から b への最小編集距離を計算する」という典型的なケースに多少似ていますが、実際にはまったく異なります。 Vue の diff は比較的軽量です。興味のある方は、関連情報を参照して詳細をご確認ください。 オリジナルリンク: https://www.qcloud.com/community/article/648055 著者: 王玉林 [この記事は、51CTOコラムニスト「Tencent Cloud Technology Community」によるオリジナル記事です。転載の許可を得るには、51CTOを通じて原著者に連絡してください。 この著者の他の記事を読むにはここをクリックしてください |
<<: IaaS とは何ですか?最新のデータセンタープラットフォーム
>>: Rancher Labs「Rancher 2.0リリースと中国ユーザーおよびパートナーカンファレンス」が盛況のうちに開催されました
desivps が LosAngelesVPS を買収してからしばらく経ちました。以前の LosAn...
企業が公式Weiboアカウントを開設し、マーケティング宣伝を行うことは、非常に重要なマーケティングプ...
[[278722]]仮想マシンJVM = クラスローダー + 実行エンジン + ランタイムデータ領...
Sogou は今年 7 月に C++ 非同期スケジューリング サーバー エンジンである Workfl...
2年前、「Jump Jump」というミニゲームプログラムがWeChat Momentsで人気を博しま...
cmivps の香港 VPS のデフォルト設定は中国本土最適化ですが、私が使用した多くのネットワーク...
[51CTO.com クイック翻訳] Kubernetes を使用してコンテナ化されたアプリケーショ...
IDC Review Network (idcps.com) は4月1日に次のように報じました。ID...
vitashost.com は設立されて間もない新しい会社です。主に米国西海岸のロサンゼルスデータセ...
レポートによると、エッジ コンピューティングには、速度の向上、レイテンシの短縮、データ セキュリティ...
実は、私が初めて SEO 業界に入ったとき、SEO の仕事は簡単ではありませんでした。毎日ニュース記...
月給5,000~50,000のこれらのプロジェクトはあなたの将来です企業は、売り上げを増やし、より多...
昨日は、都合により遅れてしまい、ホームページの「スタートラインで勝つ」コラムを更新できませんでした。...
Torqhost は 2007 年に設立された企業で、エストニアのタリンにデータセンターがあり、会社...
Baidu Shareは今でもとても便利です。最初はJIATHISを使っていましたが、他の人のブログ...