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 プライベート クラウド ストレージ ネットワーク ディスクの構築に関する詳細なチュートリアル

推薦する

docker version es、milvus、minio 起動コマンドの詳細な説明

1. es起動コマンド: docker run -itd -e TAKE_FILE_OWNERSHI...

サーバー同時実行数の推定式と計算方法

最近、サーバーのストレステストを再度行う必要が出てきました。ここでは、最近学んだ見積もりスキームと見...

mysqlはルートユーザーと一般ユーザーを作成し、機能を変更および削除します。

方法1: SET PASSWORDコマンドを使用する mysql -u ルート mysql> ...

フローティングをクリアするいくつかの方法(推奨)

1. 同じタイプの空の要素を追加し、要素の CSS 属性 clear:both; を設定します。 ...

制限およびオフセット ページング シナリオを使用すると速度が遅くなるのはなぜですか?

質問から始めましょう5 年前、私が Tencent にいたとき、ページング シナリオでは MySQL...

CSS でフロートをクリアするための完全ガイド (要約)

1. 親divは疑似クラスafterとzoomを定義します <スタイル タイプ="...

Linux 上の MYSQL 5.7 でルート パスワードを取得する際の問題 (テスト済み、利用可能)

目次1. --skip-grant-tables 経由で取得する1.1 my.conf を変更し、新...

Linuxのtimeコマンドの使い方の詳しい説明

1. コマンドの紹介時間は、コマンドの実行に費やされた時間や関連するシステム リソース、その他の情報...

Docker Desktop で rocketmq をインストールするための非常に詳細なチュートリアル

Dockerデスクトップをインストールするダウンロード先: Docker Desktop for M...

ボタンの 4 つのクリック応答方法の概要

ボタンは頻繁に使用されます。ここでは、イベント処理メソッドを整理し、実装方法が多数あることを発見しま...

シェルスクリプト nginx 自動化スクリプト

このスクリプトは、nginxの起動、停止、再起動の操作を満たすことができます。 #!/bin/bas...

MySQL slow_log テーブルを InnoDB エンジンに変更することはできません。詳細な説明

背景mysql.slow_log からスロー クエリ ログを取得するのは遅く、テーブルは csv テ...

MySQL 8.0.13 手動インストールチュートリアル

この記事では、MySQL 8.0.13の手動インストールチュートリアルを参考までに紹介します。具体的...

Vue における属性とプロパティの具体的な使用法と違い

目次Vue.jsにおける属性とプロパティ値および関連する処理として属性とプロパティの概念属性とプロパ...

HTML テーブルの行間隔を変更する方法の例

HTML テーブルを使用する場合、行間隔を変更する必要がある場合がありますが、余白、パディング、折り...