ホームページ ウェブフロントエンド jsチュートリアル diff アルゴリズムの使用スキルのまとめ

diff アルゴリズムの使用スキルのまとめ

May 11, 2018 pm 01:35 PM
diff スキル 要約する

今回は、diff アルゴリズムの使用スキルについてまとめました。実際のケースを見てみましょう。

仮想dom

diffアルゴリズムは、まずdiffのオブジェクトが仮想domであり、実際のdomの更新はdiffアルゴリズムの結果であるという概念を明確にする必要があります

Vnode基本クラス

 constructor (
  。。。
 ) {
  this.tag = tag
  this.data = data
  this.children = children
  this.text = text
  this.elm = elm
  this.ns = undefined
  this.context = context
  this.fnContext = undefined
  this.fnOptions = undefined
  this.fnScopeId = undefined
  this.key = data && data.key
  this.componentOptions = componentOptions
  this.componentInstance = undefined
  this.parent = undefined
  this.raw = false
  this.isStatic = false
  this.isRootInsert = true
  this.isComment = false
  this.isCloned = false
  this.isOnce = false
  this.asyncFactory = asyncFactory
  this.asyncMeta = undefined
  this.isAsyncPlaceholder = false
 }
ログイン後にコピー
のこの部分このコードは主に更新用です。 diff アルゴリズムの特定の diff 属性

の意味を知ることは良いことです。 もちろん、vnode インスタンス

全体のプロセス

のコア機能は patch 関数です。

isUndef判定( unknown か null か)
  • // 空のマウント(おそらくコンポーネント)、新しいルート要素を作成createElm(vnode,insertVnodeQueue) ここで、ノードの作成が1つも挿入されていないことがわかります。 1 つですが、統合バッチ処理のためにキューに入れられます
  • コア関数 SameVnode
  • function sameVnode (a, b) {
     return (
      a.key === b.key && (
       (
        a.tag === b.tag &&
        a.isComment === b.isComment &&
        isDef(a.data) === isDef(b.data) &&
        sameInputType(a, b)
       ) || (
        isTrue(a.isAsyncPlaceholder) &&
        a.asyncFactory === b.asyncFactory &&
        isUndef(b.asyncFactory.error)
       )
      )
     )
    }
    ログイン後にコピー
    これは、2 つのノードのキー、タグ (ラベル)、およびデータを直接比較する外部比較関数です (ここでのデータは VNodeData を指します)、入力タイプを直接比較します。
export interface VNodeData {
 key?: string | number;
 slot?: string;
 scopedSlots?: { [key: string]: ScopedSlot };
 ref?: string;
 tag?: string;
 staticClass?: string;
 class?: any;
 staticStyle?: { [key: string]: any };
 style?: object[] | object;
 props?: { [key: string]: any };
 attrs?: { [key: string]: any };
 domProps?: { [key: string]: any };
 hook?: { [key: string]: Function };
 on?: { [key: string]: Function | Function[] };
 nativeOn?: { [key: string]: Function | Function[] };
 transition?: object;
 show?: boolean;
 inlineTemplate?: {
  render: Function;
  staticRenderFns: Function[];
 };
 directives?: VNodeDirective[];
 keepAlive?: boolean;
}
ログイン後にコピー
これにより、2 つのノードにさらなる比較値があるかどうかが確認され、そうでない場合は直接置換されます

置換プロセスは主に createElm 関数であり、もう 1 つは oldVNode を破棄することです

// destroy old node
    if (isDef(parentElm)) {
     removeVnodes(parentElm, [oldVnode], 0, 0)
    } else if (isDef(oldVnode.tag)) {
     invokeDestroyHook(oldVnode)
    }
ログイン後にコピー
簡略化して挿入プロセスノードのタイプを決定し、それを個別に呼び出すことです

createComponent (子があるかどうかを決定し、それを再帰的に呼び出します)

createComment

createTextNode

作成後に挿入関数を使用します

その後、次のことを行う必要がありますハイドレート関数を使用して、仮想 dom と実際の dom をマッピングします

function insert (parent, elm, ref) {
  if (isDef(parent)) {
   if (isDef(ref)) {
    if (ref.parentNode === parent) {
     nodeOps.insertBefore(parent, elm, ref)
    }
   } else {
    nodeOps.appendChild(parent, elm)
   }
  }
 }
ログイン後にコピー

core 関数

 function patchVnode (oldVnode, vnode, insertedVnodeQueue, removeOnly) {
  if (oldVnode === vnode) {
   return
  }
  const elm = vnode.elm = oldVnode.elm
  if (isTrue(oldVnode.isAsyncPlaceholder)) {
   if (isDef(vnode.asyncFactory.resolved)) {
    hydrate(oldVnode.elm, vnode, insertedVnodeQueue)
   } else {
    vnode.isAsyncPlaceholder = true
   }
   return
  }
  if (isTrue(vnode.isStatic) &&
   isTrue(oldVnode.isStatic) &&
   vnode.key === oldVnode.key &&
   (isTrue(vnode.isCloned) || isTrue(vnode.isOnce))
  ) {
   vnode.componentInstance = oldVnode.componentInstance
   return
  }
  let i
  const data = vnode.data
  if (isDef(data) && isDef(i = data.hook) && isDef(i = i.prepatch)) {
   i(oldVnode, vnode)
  }
  const oldCh = oldVnode.children
  const ch = vnode.children
  if (isDef(data) && isPatchable(vnode)) {
   for (i = 0; i < cbs.update.length; ++i) cbs.update[i](oldVnode, vnode)
   if (isDef(i = data.hook) && isDef(i = i.update)) i(oldVnode, vnode)
  }
  if (isUndef(vnode.text)) {
   if (isDef(oldCh) && isDef(ch)) {
    if (oldCh !== ch) updateChildren(elm, oldCh, ch, insertedVnodeQueue, removeOnly)
   } else if (isDef(ch)) {
    if (isDef(oldVnode.text)) nodeOps.setTextContent(elm, &#39;&#39;)
    addVnodes(elm, null, ch, 0, ch.length - 1, insertedVnodeQueue)
   } else if (isDef(oldCh)) {
    removeVnodes(elm, oldCh, 0, oldCh.length - 1)
   } else if (isDef(oldVnode.text)) {
    nodeOps.setTextContent(elm, &#39;&#39;)
   }
  } else if (oldVnode.text !== vnode.text) {
   nodeOps.setTextContent(elm, vnode.text)
  }
  if (isDef(data)) {
   if (isDef(i = data.hook) && isDef(i = i.postpatch)) i(oldVnode, vnode)
  }
 }
ログイン後にコピー
const el = vnode.el = oldVnode.el これは非常に重要なステップです。vnode.el に現在の実際の dom を参照させます。 dom が変更されると、vnode.el も同期して変更されます。

2つの参照が一致しているか比較してください
  1. その後asyncFactoryが何をするのか分からないので理解するのが難しいです
  2. 静的ノードはキーが同じであれば比較します。再レンダリングされず、componentInstance は直接コピーされます (ここでコマンドが有効になると)
  3. vnode がテキスト ノードまたは
  4. annotation
  5. ノードである場合、vnode.text != oldVnode.text のみが必要です。 vnode.elm のテキストコンテンツを更新します

    子の比較
oldVnode のみに子ノードがある場合は、これらのノードを削除します
  • vnode のみに子ノードがある場合は、ここでこれらの子ノードを作成しますoldVnode がテキスト ノードの場合、vnode.elm を配置します。テキストが空の文字列
  • に設定されている場合、updateChildren が更新されます。これについては後で詳しく説明します

  • oldVnode にも vnode にも子ノードがない場合、ただし、oldVnode はテキスト ノードまたはコメント ノードです。vnode.elm を追加します。テキストは空の文字列に設定されます

  • updateChildren

この部分の焦点は依然としてアルゴリズム全体にあります最初の 4 つのポインター、oldStart 、oldEnd、newStart、newEnd、2 つの配列、oldVnode、Vnode。

function updateChildren (parentElm, oldCh, newCh, insertedVnodeQueue, removeOnly) {
  let oldStartIdx = 0
  let newStartIdx = 0
  let oldEndIdx = oldCh.length - 1
  let oldStartVnode = oldCh[0]
  let oldEndVnode = oldCh[oldEndIdx]
  let newEndIdx = newCh.length - 1
  let newStartVnode = newCh[0]
  let newEndVnode = newCh[newEndIdx]
  let oldKeyToIdx, idxInOld, vnodeToMove, refElm
  while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {
   if (isUndef(oldStartVnode)) {
    oldStartVnode = oldCh[++oldStartIdx] // Vnode has been moved left
   } else if (isUndef(oldEndVnode)) {
    oldEndVnode = oldCh[--oldEndIdx]
   } else if (sameVnode(oldStartVnode, newStartVnode)) {
    patchVnode(oldStartVnode, newStartVnode, insertedVnodeQueue)
    oldStartVnode = oldCh[++oldStartIdx]
    newStartVnode = newCh[++newStartIdx]
   } else if (sameVnode(oldEndVnode, newEndVnode)) {
    patchVnode(oldEndVnode, newEndVnode, insertedVnodeQueue)
    oldEndVnode = oldCh[--oldEndIdx]
    newEndVnode = newCh[--newEndIdx]
   } else if (sameVnode(oldStartVnode, newEndVnode)) { // Vnode moved right
    patchVnode(oldStartVnode, newEndVnode, insertedVnodeQueue)
    canMove && nodeOps.insertBefore(parentElm, oldStartVnode.elm, nodeOps.nextSibling(oldEndVnode.elm))
    oldStartVnode = oldCh[++oldStartIdx]
    newEndVnode = newCh[--newEndIdx]
   } else if (sameVnode(oldEndVnode, newStartVnode)) { // Vnode moved left
    patchVnode(oldEndVnode, newStartVnode, insertedVnodeQueue)
    canMove && nodeOps.insertBefore(parentElm, oldEndVnode.elm, oldStartVnode.elm)
    oldEndVnode = oldCh[--oldEndIdx]
    newStartVnode = newCh[++newStartIdx]
   } else {
    if (isUndef(oldKeyToIdx)) oldKeyToIdx = createKeyToOldIdx(oldCh, oldStartIdx, oldEndIdx)
    idxInOld = isDef(newStartVnode.key)
     ? oldKeyToIdx[newStartVnode.key]
     : findIdxInOld(newStartVnode, oldCh, oldStartIdx, oldEndIdx)
    if (isUndef(idxInOld)) { // New element
     createElm(newStartVnode, insertedVnodeQueue, parentElm, oldStartVnode.elm, false, newCh, newStartIdx)
    } else {
     vnodeToMove = oldCh[idxInOld]
     if (sameVnode(vnodeToMove, newStartVnode)) {
      patchVnode(vnodeToMove, newStartVnode, insertedVnodeQueue)
      oldCh[idxInOld] = undefined
      canMove && nodeOps.insertBefore(parentElm, vnodeToMove.elm, oldStartVnode.elm)
     } else {
      // same key but different element. treat as new element
      createElm(newStartVnode, insertedVnodeQueue, parentElm, oldStartVnode.elm, false, newCh, newStartIdx)
     }
    }
    newStartVnode = newCh[++newStartIdx]
   }
  }
  if (oldStartIdx > oldEndIdx) {
   refElm = isUndef(newCh[newEndIdx + 1]) ? null : newCh[newEndIdx + 1].elm
   addVnodes(parentElm, refElm, newCh, newStartIdx, newEndIdx, insertedVnodeQueue)
  } else if (newStartIdx > newEndIdx) {
   removeVnodes(parentElm, oldCh, oldStartIdx, oldEndIdx)
  }
 }
ログイン後にコピー

ループ比較のいくつかの状況と処理 (以下の ++ -- すべてインデックスの ++ を参照します --) 比較は比較対象のノードです。この比較では、sameVnode 関数が使用されます。これは当てはまりません

ループ全体が終了しないための条件 oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx

oldStart === newStart, oldStart++ newStart++

  1. oldEnd === newEnd 、 oldEnd-- newEnd--

  2. oldStart === newEnd、oldStart はキューの最後に挿入されます oldStart++ newEnd--

  3. oldEnd === newStart、oldEnd はキューの先頭に挿入されます oldEnd- - newStart++

  4. 残りの状況はすべてこのように処理されます。 簡単に言うと、処理後に newStart++

    の 2 つのプロセスがあります。
  • newStart在old中发现一样的那么将这个移动到oldStart前

  • 没有发现一样的那么创建一个放到oldStart之前

循环结束后并没有完成

还有一段判断才算完

if (oldStartIdx > oldEndIdx) {
   refElm = isUndef(newCh[newEndIdx + 1]) ? null : newCh[newEndIdx + 1].elm
   addVnodes(parentElm, refElm, newCh, newStartIdx, newEndIdx, insertedVnodeQueue)
  } else if (newStartIdx > newEndIdx) {
   removeVnodes(parentElm, oldCh, oldStartIdx, oldEndIdx)
  }

相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!

推荐阅读:

axios发送post请求提交图片表单步骤详解

axios+post方法提交formdata步骤详解

以上がdiff アルゴリズムの使用スキルのまとめの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

定量的な財務分析に Go 言語を使用するにはどうすればよいですか? 定量的な財務分析に Go 言語を使用するにはどうすればよいですか? Jun 11, 2023 am 08:51 AM

現代の金融の分野では、データサイエンスと人工知能技術の台頭により、定量的金融が徐々に重要な方向になってきています。 Go 言語は、データを効率的に処理し、分散システムを展開できる静的型プログラミング言語として、クオンツ ファイナンスの分野で徐々に注目を集めています。この記事では、Go 言語を使用して定量的な財務分析を行う方法を紹介します 具体的な内容は次のとおりです: 財務データの取得 まず、財務データを取得する必要があります。 Go 言語のネットワーク プログラミング機能は非常に強力で、さまざまな財務データを取得するために使用できます。比較する

Linux システムでの system() 関数の使用法の概要 Linux システムでの system() 関数の使用法の概要 Feb 23, 2024 pm 06:45 PM

Linux での system() 関数の概要 Linux システムでは、system() 関数は非常に一般的に使用される関数であり、コマンド ライン コマンドの実行に使用できます。この記事では、system() 関数を詳細に紹介し、いくつかの具体的なコード例を示します。 1. system() 関数の基本的な使用法 system() 関数の宣言は次のとおりです: intsystem(constchar*command); コマンド パラメーターは文字です。

PHP を使用して簡単な SEO 最適化関数を開発する方法 PHP を使用して簡単な SEO 最適化関数を開発する方法 Sep 20, 2023 pm 04:18 PM

PHP を使用して簡単な SEO 最適化機能を開発する方法 SEO (SearchEngineOptimization)、または検索エンジン最適化とは、Web サイトの構造とコンテンツを改善することで検索エンジンでの Web サイトのランキングを向上させ、それによってより多くのオーガニック トラフィックを獲得することを指します。 Web サイト開発において、PHP を使用して簡単な SEO 最適化機能を実装するにはどうすればよいでしょうか?この記事では、開発者が PHP プロジェクトに SEO 最適化を実装するのに役立つ、一般的に使用される SEO 最適化テクニックと具体的なコード例をいくつか紹介します。 1. 使いやすい

nginx を使用してホットリンクを防ぐ方法 nginx を使用してホットリンクを防ぐ方法 Jun 11, 2023 pm 01:25 PM

インターネットの普及に伴い、写真や動画などの外部リンク機能を提供するWebサイトが増えています。しかし、この外部リンク機能は盗まれやすいのです。ホットリンクとは、他の Web サイトがあなたの Web サイト上の写真、ビデオ、その他のリソースを使用し、それらのリソースを独自のサーバーにダウンロードするのではなく、参照アドレスを通じて自分の Web サイトに直接表示することを意味します。このようにして、ホットリンク Web サイトは Web サイトのトラフィックと帯域幅のリソースを無料で使用できるため、リソースが無駄になり、Web サイトの速度に影響を与えます。この問題に対処するには、Nginx を使用してホットリンクを防ぐことができます。 Nginxは

データマイニングに Go 言語を使用するにはどうすればよいですか? データマイニングに Go 言語を使用するにはどうすればよいですか? Jun 10, 2023 am 08:39 AM

ビッグデータとデータマイニングの台頭により、ますます多くのプログラミング言語がデータマイニング機能をサポートし始めています。 Go 言語は、高速、安全、効率的なプログラミング言語として、データ マイニングにも使用できます。では、Go 言語をデータマイニングに使用するにはどうすればよいでしょうか?ここでは、重要な手順とテクニックをいくつか紹介します。データの取得 まず、データを取得する必要があります。これは、Web ページ上の情報のクローリング、API を使用したデータの取得、データベースからのデータの読み取りなど、さまざまな手段を通じて実現できます。 Go 言語にはリッチ HTTP が付属しています

C# を使用して最小スパニング ツリー アルゴリズムを作成する方法 C# を使用して最小スパニング ツリー アルゴリズムを作成する方法 Sep 19, 2023 pm 01:55 PM

C# を使用して最小スパニング ツリー アルゴリズムを作成する方法. 最小スパニング ツリー アルゴリズムは、グラフの接続性の問題を解決するために使用される重要なグラフ理論アルゴリズムです。コンピューター サイエンスでは、最小スパニング ツリーとは、スパニング ツリーのすべてのエッジの重みの合計が最小となる、接続されたグラフのスパニング ツリーを指します。この記事では、C# を使用して最小限のスパニング ツリー アルゴリズムを作成する方法を紹介し、具体的なコード例を示します。まず、問題を表すグラフ データ構造を定義する必要があります。 C# では、隣接行列を使用してグラフを表現できます。隣接行列は、各要素が表す 2 次元配列です。

svn diff を vimdiff に置き換えます: コードを比較するためのツール svn diff を vimdiff に置き換えます: コードを比較するためのツール Jan 09, 2024 pm 07:54 PM

Linux では、svndiff コマンドを直接使用してコードの変更を表示するのは非常に難しいため、インターネット上でより良い解決策を探しました。それは、特に使用に慣れている人向けに、svndiff のコード表示ツールとして vimdiff を使用することです。 vim. とても便利です。 svndiff コマンドを使用して特定のファイルの変更を比較する場合、たとえばコマンド $svndiff-r4420ngx_http_limit_req_module.c を実行すると、実際にはコマンド -u-Lngx_http_limit_req_module.c がデフォルトの差分プログラムに送信されます。 (改訂 4420)-Lngx_

conda仮想環境の利点と運用テクニックをマスターする conda仮想環境の利点と運用テクニックをマスターする Feb 18, 2024 pm 07:46 PM

conda 仮想環境の利点と使用テクニックを理解するには、具体的なコード例が必要です Python は、科学計算、データ分析、人工知能などの分野で広く使用されている非常に人気のあるプログラミング言語です。 Python エコシステムには、多数のサードパーティ ライブラリとツールがあり、プロジェクトごとに異なるバージョンのライブラリを使用する必要がある場合があります。これらのライブラリの依存関係を管理するには、conda 仮想環境が重要なツールになります。 conda は、簡単に作成および実行できるオープンソースのパッケージ管理システムおよび環境管理システムです。

See all articles