Vue の DOM の非同期更新の簡単な分析

Vue の DOM の非同期更新の簡単な分析

データ オブジェクト: vue の data メソッドによって返されるオブジェクト。

Dep オブジェクト: 各データ属性は、このデータを使用するすべての Watcher オブジェクトを収集するための Dep を作成します。

ウォッチャーオブジェクト: 主にDOMのレンダリングに使用されます

Vue が DOM を非同期更新する原理

Vue でのデータ更新は非同期であるため、データを変更した後、変更された DOM 要素をすぐに取得することはできません。

1 実際の DOM 要素を取得できるのはいつですか?

Vue の nextTick コールバック内。

2 Vue は最新の DOM を取得するために nextTick メソッドを使用する必要があるのはなぜですか?

2.1 vue が Watcher を呼び出してビューを更新する場合、直接更新するのではなく、更新する必要がある Watcher を Queue キューに追加し、特定の更新メソッド flushSchedulerQueue を nexTick に渡して呼び出します。

// src > core > observer > watcher.js + scheduler.js // データが更新されると、次のコードが順番に実行されます // 1. Data.set をトリガーします
// 2. dep.notifyを呼び出す
// 3. Dep は関連するすべての Watcher を走査し、更新メソッドを実行します。class Watcher {
  // 4. 更新操作を実行する update() {
    キューウォッチャー(これ);
  }
}

定数キュー = [];

関数queueWatcher(ウォッチャー: ウォッチャー) {
  // 5. 現在の Watcher を非同期キューに追加します。queue.push(watcher);
  // 6. 非同期キューを実行し、コールバック nextTick(flushSchedulerQueue); を渡します。
}

// ビューを更新するための特定のメソッド function flushSchedulerQueue() {
  ウォッチャー、ID;
  // ソートし、最初に親ノードをレンダリングしてから、子ノードをレンダリングします。 // これにより、次のような不要な子ノードのレンダリングを回避できます。親ノードで v-if が false である子ノードはレンダリングする必要がありません。 queue.sort((a, b) => a.id - b.id);
  // バッチ更新のためにすべてのウォッチャーを走査します。
  (インデックス = 0; インデックス < キューの長さ; インデックス++) {
    ウォッチャー = キュー[インデックス];
    // DOMを更新する
    ウォッチャーを実行します。
  }
} 

2.2 nextTick -- 渡された flushSchedulerQueue をコールバック配列に追加し、timerFunc メソッドを実行します。

const コールバック = [];
timerFunc を作成します。

関数 nextTick(cb?: 関数、ctx?: オブジェクト) {
  _resolve を実行します。
  // 1. 渡されたflushSchedulerQueueメソッドをコールバック配列に追加します callbacks.push(() => {
    cb.call(ctx);
  });
  // 2. 非同期タスクを実行する // このメソッドは、ブラウザの互換性に応じて異なる非同期戦略 timerFunc() を選択します。
}

2.3 timerFunc メソッド - ブラウザの互換性に基づいて作成された非同期メソッドです。このメソッドを実行すると、flushSchedulerQueue メソッドが呼び出され、特定の DOM 更新が実行されます。

timerFunc を作成します。
// Promiseと互換性があるかどうかを判定する
if (typeof Promise !== "undefined") {
  タイマー関数 = () => {
    Promise.resolve() を実行してから (コールバックをフラッシュします);
  };
  // MutationObserverと互換性があるかどうかを判定する
  // https://developer.mozilla.org/zh-CN/docs/Web/API/MutationObserver
} そうでない場合 (typeof MutationObserver !== "undefined") {
  カウンターを1にします。
  const オブザーバー = 新しい MutationObserver(flushCallbacks);
  定数textNode = document.createTextNode(String(counter));
  オブザーバー.observe(textNode, {
    文字データ: true、
  });
  タイマー関数 = () => {
    カウンター = (カウンター + 1) % 2;
    textNode.data = String(カウンター);
  };
  // setImmediateと互換性があるかどうかを判定する
  // このメソッドは一部の IE ブラウザに存在します} else if (typeof setImmediate !== "undefined") {
  // これはマクロタスクですが、setTimeout よりも優れています timerFunc = () => {
    即時設定(コールバックをフラッシュ)。
  };
} それ以外 {
  // 上記の方法がわからない場合は、setTimeout 0 を使用します
  タイマー関数 = () => {
    タイムアウトを設定します(コールバックをフラッシュします、0);
  };
}

// 非同期実行後、すべてのコールバックメソッドを実行します。つまり、flushSchedulerQueueを実行します。
関数flushCallbacks() {
  (i = 0 とします; i < コピー数.長さ; i++) {
    コールバック[i]();
  }
} 

2.4 論理的判断力を向上させる

2.4.1 同じウォッチャーをキューに追加しないように、has フラグを決定します。

2.4.2 待機フラグを決定し、1ティック以内にすべてのウォッチャーを更新します。

2.4.3 フラッシュ フラグを決定し、Watcher がレンダリングされるときに生成される可能性のある新しい Watcher を処理します。

v-if 条件がトリガーされると、新しく追加された Watcher がレンダリングされます。

ヒント: nextTick は、Promise、setTimeout、その他のメソッドによってシミュレートされる単なる非同期タスクです。

3 なぜ this.$nextTick は更新された DOM を取得できるのでしょうか?

this.$nextTick を呼び出すと、実際には図の nextTick メソッドが呼び出され、非同期キュー内のコールバック関数が実行されます。先入先出の原則に従って、データの変更によってトリガーされた更新非同期キューが最初に実行されます。実行が完了すると、新しい DOM が生成されます。次に this.$nextTick のコールバック関数が実行されると、更新された DOM 要素を取得できます。

// this.$nextTick を使用して nextTick メソッドを呼び出します Vue.prototype.$nextTick = function (fn: Function) {
  nextTick(fn, this) を返します。
};

要約: Vue 非同期更新の原則

Vue のデータが変更されると、このデータに関連するすべてのウォッチャーが更新をトリガーされます。まず、すべてのウォッチャーがキューに追加されます。次に、nextTick メソッドを呼び出して非同期タスクを実行します。非同期タスクのコールバックでは、キュー内のウォッチャーをソートし、対応する DOM 更新を実行します。

Vue の DOM 非同期更新の実装に関するこの記事はこれで終わりです。Vue の DOM 非同期更新に関するより関連性の高いコンテンツについては、123WORDPRESS.COM の以前の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • VUE は DOM を非同期的に更新します - $nextTick を使用して DOM ビューの問題を解決します
  • Vue.js ソースコードからの非同期 DOM 更新戦略と nextTick の詳細な説明
  • Vue バッチ更新 DOM 実装手順

<<:  MySQLは「order by」がどのように機能するかを簡単に理解します

>>:  NextCloud プライベート クラウド ストレージ ネットワーク ディスクの構築に関する詳細なチュートリアル

推薦する

mysqlパラメータsql_safe_updatesを使用して更新/削除範囲を制限する方法の詳細な説明

序文皆さんご存知のとおり、MySQL の運用・保守において、更新/削除条件が誤っているためにデータが...

Reactはダブルスライダークロススライドを実装します

この記事では、Reactでダブルスライダークロススライドを実装するための具体的なコードを参考までに共...

Linux ファイル記述子、ファイルポインタ、および inode の詳細

目次Linux - ファイル記述子、ファイルポインタ、インデックスノード1. Linux - ファイ...

nginx proxy_cache バッチキャッシュクリアスクリプトの紹介

前書き: 以前、公式の nginx proxy_cache を CDN 静的キャッシュとして使用して...

一般的な HBase 運用および保守ツール 10 個の概要

概要: HBase には、ユーザーに管理、分析、修復、デバッグ機能を提供するための多くの操作および保...

MySQL 5.7.18 のダウンロードとインストールの詳細な手順

MySql ダウンロード1. 公式サイトを開き、ダウンロード パスを見つけます。ダウンロード アドレ...

「MySQL サービスを開始できません エラー 1069」を解決する方法

今日、外出中に同僚から、ウェブサイトのバックエンドにアクセスできないというメッセージが届きました。と...

JSON.stringify の簡易版の実装とその 6 つの主要機能の詳細な説明

目次序文JSON.stringify の 6 つの機能特集1特集2特集3特集4特集5特集6手動で文字...

Nexus を使用して Docker リポジトリを作成する方法

公式の Docker レジストリを使用して作成されたウェアハウスでは、イメージを削除してもデフォルト...

Docker に Elasticsearch 7.6.2 をインストールするチュートリアル

DockerをインストールするDocker をインストールする必要がありますが、それ以上の指示はあり...

エージェントを介したzabbix監視プロセスとポートの詳細なプロセス

環境の紹介オペレーティングシステム: Centos 7.4 Zabbix バージョン: zabbix...

mysql の認証、起動、およびサービスの起動のための一般的なコマンド

1. 4つの起動方法: 1.mysqld MySQL サーバーを起動します: ./mysqld --...

MySQLの重複排除操作を極限まで最適化する方法

目次1. インデックスと変数の賢い使用1. インデックスなしの比較テスト2. created_tim...

MySQLの制限を使用して大規模なページングの問題を解決する方法

序文日常の開発では、MySQL を使用してページングを実装する場合、常に MySQL 制限構文を使用...

HTML フォームを送信するいくつかの方法_PowerNode Java Academy

方法1: 送信ボタンから送信する <!DOCTYPE html> <html>...