Vueの最初のレンダリングのプロセス全体についての簡単な説明

Vueの最初のレンダリングのプロセス全体についての簡単な説明

昨日、友人から、ページが最初に読み込まれたときに Vue は何をするのかと尋ねられました。この質問は、多くの友人の心の中で漠然としているようです。今日は、Vue の最初のレンダリング プロセスを詳しく見てみましょう。

Vueの最初のレンダリングのプロセス全体を理解するには、どこから始めるべきでしょうか?明らかに、エントリファイル、つまりmain.jsから始める必要があります。

1. Vueの初期化

まず、main.js を見てみましょう。最初で最も重要なことは、vue を導入することです。

'vue' から vue をインポートします

実際、vueがパッケージ化された後、distフォルダには複数のバージョンがあります。
ユニバーサルバージョン(UMD) :フルバージョンのvue.jsとランタイムバージョンのvue.runtime.js
CommonJs バージョン: vue.common.js のフル バージョンと vue.runtime.common.js のランタイム バージョン
ES モジュールのバージョン: vue.esm.js のフル バージョンと vue.runtime.esm.js のランタイム バージョン
一般的に、vue 2.6 以降、vue/cli で作成するプロジェクトでは vue.runtime.esm.js ランタイム バージョンが使用されます。つまり、vue を導入すると、vue.esm.js バージョンが導入されることになります。

では、vue が導入された後、vue 内の関連コードは実行されるのでしょうか? Vueソースコード内のどのコードが最も最近実行されたか(導入されたVueはVueソースコードにパッケージ化されたVueです)を知るには、まずエントリファイルがどこにあるかを知る必要があります。

vue エントリ ファイル

Vueのエントリファイルは主にVueソースコード構造のsrc/platforms/webの下にあります。

ここに画像の説明を挿入

Vue をパッケージ化するときに、パッケージ化用に異なる Vue エントリ ファイルを選択できます。エントリ ファイルが異なると、異なる Vue バージョンがパッケージ化されます。
ここでは主にentry-runtime-with-compiler.jsの完全版について説明します。
まずフルバージョンとランタイムバージョンの違いを理解しましょう

フルバージョンとランタイムバージョンの違い

フルバージョンは、ランタイムバージョン + コンパイラの組み合わせです。ランタイムバージョンにはコンパイラがありません。つまり、テンプレートコンパイル機能はありません。主に Vue インスタンスの作成と仮想 DOM のレンダリングに使用されます。より小さく、より軽量(コンパイラのコードは 3,000 行以上)
それはどういう意味ですか?

<本文>
	<div id="アプリ">
		<p>私はindex.htmlのコンテンツです</p>
	</div>
</本文>
新しいVue({
	テンプレート: '<div>私はテンプレートによってレンダリングされたコンテンツです</div>'
}).$mount('#app')

上記の状況、
フルバージョンの vue であれば、コンパイラーが用意されており、new Vue 時に渡されたテンプレートをレンダリング関数にコンパイルし、options の render 属性に割り当てます。その後、$mount の後にレンダリング関数を仮想 DOM にレンダリングし、仮想 DOM を実際の DOM に変換します。そのため、最終ページには「私はテンプレート template によってレンダリングされたコンテンツです」という文が表示されます。元の文章は上書きされます。

ランタイムバージョンの場合、コンパイラは存在せず、テンプレート内のコンテンツはコンパイルされないため、ページには元のDOMのみが含まれる。

では、下を見てエントリファイルを探しましょう。何が実行されるかを見てみましょう。

ここに画像の説明を挿入

エントリファイルは最初にvueをインポートし、その後いくつかの処理を経て、最後にvueをエクスポートしていることがわかります。
まず、Vue のパスをインポートして、Vue コンストラクターが作成される場所を段階的に確認します。上記のように、vueはruntime/indexからインポートされているので、runtime/indexに移動しましょう。

ここに画像の説明を挿入

このファイルも同じです。vueをインポートし、いくつかの処理を行ってからvueをエクスポートします。core/indexを探してみましょう。

ここに画像の説明を挿入

このファイルについても同じことが言えます。検索を続けて./instance/indexを見つけましょう。

ここに画像の説明を挿入

ここでは、ソース コードの src/core/instance/index.js ファイルにある vue コンストラクターの作成が見つかります。

そして、上記の参照関係から、Vueをプロジェクトに導入した後、最初に実行されるファイルの順序は次のようになります。

src/core/instace/index.js ===> 1
src/core/index.js ===> 2
src/platforms/web/runtime/index.js ===> 3
src/platforms/web/entry-runtime-with-compiler.js 4

それでは、各ファイルが何を実行するか見てみましょう。
まず src/core/instace/index.js

1.1、src/core/instace/index.js

まず、このファイルはvueコンストラクタを定義し、いくつかのvueインスタンスプロパティとインスタンスメソッドを初期化します。つまり、vue.prototypeプロトタイプの下にさまざまなメソッドとプロパティが追加されます。

ここに画像の説明を挿入

次に、各メソッドによって Vue のどのインスタンス プロパティまたはメソッドが初期化されるかを詳しく見てみましょう。

1.1.1、initMixin(Vue)

ここに画像の説明を挿入

1.1.2、stateMixin(Vue)

ここに画像の説明を挿入

1.1.3、イベントMixin(Vue)

ここに画像の説明を挿入

1.1.4、ライフサイクルミックスイン(Vue)

ここに画像の説明を挿入

1.1.5、レンダリングミックスイン(Vue)

ここに画像の説明を挿入

src/core/instace/index.jsが実行された後、次のファイルの実行が続行されます。

エクスポート関数 initGlobalAPI (Vue: GlobalAPI) {
  // 設定
  定数configDef = {}
  configDef.get = () => 設定
  process.env.NODE_ENV !== 'production' の場合 {
    configDef.set = () => {
      警告(
        「Vue.config オブジェクトを置き換えないで、代わりに個々のフィールドを設定してください。」
      )
    }
  }
  // 新しい設定プロパティを追加しました Object.defineProperty(Vue, 'config', configDef)

  // 新しい静的メンバー util を追加しました
  Vue.util = {
    警告する、
    伸ばす、
    マージオプション、
    定義Reactive
  }

  // 3 つの静的メンバーを追加 set delete nextTick
  Vue.set = 設定
  Vue.delete = del
  Vue.nextTick = 次のティック

  // 新しい静的メンバー observable を追加しました
  Vue.observable = <T>(obj: T): T => {
    観察する(obj)
    オブジェクトを返す
  }

  // オプションを初期化します。オプションは空のオブジェクトです。</T>
  Vue.options = Object.create(null)
  ASSET_TYPES.forEach(タイプ => {
    Vue.options[type + 's'] = Object.create(null)
  })

  Vue.options._base = Vue

  // グローバル コンポーネント keep-alive を登録します。builtInComponents 内には keep-alive コンポーネントがあります。export extend(Vue.options.components,builtInComponents)

  // 以下は初期化されます Vue.use() Vue.mixin() Vue.extend() 
  initUse(Vue)
  initMixin(Vue)
  initExtend(Vue)
  // Vue.directive()、Vue.component()、vue.filter() を初期化します
  アセットレジスタの初期化(Vue)
}

1.2、src/core/index.js

ここに画像の説明を挿入

このファイルは主に、Vue に多くの静的インスタンス メソッドとプロパティを追加していることがわかります。具体的には何が追加されるのでしょうか?
実行されるメソッドinitGlobalAPI(Vue)を見てみましょう。

1.2.1 initGlobalAPI(Vue)

エクスポート関数 initGlobalAPI (Vue: GlobalAPI) {
  // 設定
  定数configDef = {}
  configDef.get = () => 設定
  process.env.NODE_ENV !== 'production' の場合 {
    configDef.set = () => {
      警告(
        「Vue.config オブジェクトを置き換えないで、代わりに個々のフィールドを設定してください。」
      )
    }
  }
  // 新しい設定プロパティを追加しました Object.defineProperty(Vue, 'config', configDef)

  // 新しい静的メンバー util を追加しました
  Vue.util = {
    警告する、
    伸ばす、
    マージオプション、
    定義Reactive
  }

  // 3 つの静的メンバーを追加 set delete nextTick
  Vue.set = 設定
  Vue.delete = del
  Vue.nextTick = 次のティック

  // 新しい静的メンバー observable を追加しました
  Vue.observable = <T>(obj: T): T => {
    観察する(obj)
    オブジェクトを返す
  }

  // オプションを初期化します。オプションは空のオブジェクトです。</T>
  Vue.options = Object.create(null)
  ASSET_TYPES.forEach(タイプ => {
    Vue.options[type + 's'] = Object.create(null)
  })

  Vue.options._base = Vue

  // グローバル コンポーネント keep-alive を登録します。builtInComponents 内には keep-alive コンポーネントがあります。export extend(Vue.options.components,builtInComponents)

  // 以下は初期化されます Vue.use() Vue.mixin() Vue.extend() 
  initUse(Vue)
  initMixin(Vue)
  initExtend(Vue)
  // Vue.directive()、Vue.component()、vue.filter() を初期化します
  アセットレジスタの初期化(Vue)
}

1.3、src/platforms/web/runtime/index.js

ここに画像の説明を挿入

1.4、src/platforms/web/entry-runtime-with-compiler.js

ここに画像の説明を挿入

このファイルの主な機能は、vue プロトタイプの下の $mount メソッドを書き換えることです。 $mount メソッドで何が行われるかについては後ほど説明します。

1.5. Vue初期化の概要

上記のプロセス全体は、ユーザーがvueを使用するときにvueファイルをインポートした直後に実行されるものです。

これらが実行された後、プロジェクト内の main.js ファイルの実行が継続されますか?
これは実行されます

新しいVue({
  ルーター、
  店、
  レンダリング: h => h(App)
}).$mount('#app')

この時点で、vueコンストラクタが呼び出され始めます。

2. Vueコンストラクタの実行

この時点で、vue コンストラクターが最初に実行されます。

ここに画像の説明を挿入

_initメソッドが主に実行されていることがわかります。ここからVueのライフサイクルが実行され始めます。

ここに画像の説明を挿入

上記は、_init() メソッドのコードの中で最も重要な部分です (コードが多すぎるため、すべてのスクリーンショットは撮りません。ソース コードを自分で確認できます)。次のことがわかります。

2.1. beforeCreateフック

ライフサイクルの beforeCreate フックの前に、vue が行う主なことは、vue プロトタイプにさまざまなプロパティとメソッドを追加し、vue にさまざまな静的プロパティとメソッドを追加し、vm インスタンスにさまざまなプロパティとメソッドを追加することです。

2.2、フック作成

上の図からわかるように、beforeCreateフックが実行された後、主にinitInjections、initState、initProvideの3つのメソッドが実行されます。

// VMインスタンスに注入する callHook(vm, 'beforeCreate')

// VMインスタンスに注入する initInjections(vm)

// VM の $props、$methods、$data、computed、watch を初期化します
初期化状態(vm)

// provide を vm インスタンスに注入する initProvide(vm)

//作成されたライフサイクルを実行する callHook(vm, 'created')

実際、焦点は initState(vm) メソッドにあり、このメソッドでは、vm インスタンスの $props、$data、$methods、computed、watch などが初期化されます。同時に、その内部で initData() メソッドが呼び出され、observer() メソッドを呼び出して、データ内のすべてのデータをレスポンシブ データに変換します。つまり、データ インターセプターを追加します。

したがって、create ライフサイクルの前に、vm の $props、$data、$methods、computed、および watch プロパティが初期化されることがわかります。
したがって、データ内のさまざまなデータを create で呼び出したり、props やメソッドなどのさまざまなメソッドを呼び出すことができるのはそのためです。

作成したライフサイクルが完了したら、下を見続けます

ここに画像の説明を挿入

ここでは、vm.$options.el が存在するかどうか、また vm.$options.el が何であるかが判断されていることがわかります。
new Vue ({}) が呼び出されると、渡されたオブジェクトのすべてのプロパティがオプションの下にマウントされます。

新しいVue({
  el: '#app'
  ルーター、
  店、
  レンダリング: h => h(App)
})

したがって、vm.$options.el は上記で渡された el です。
ここで、el が存在するかどうかを確認します。存在する場合は、$mount の実行を続行します。

すると誰もが好奇心を持つでしょうが、それが存在しないと、行き詰まり、前に進めなくなります。はい、そうでない場合は続行されません。コードを続行したい場合は、$mount メソッドを実行する必要があります。
ここで、Vue の一般的な使い方を見てみましょう。

新しいVue({
  ルーター、
  店、
  レンダリング: h => h(App)
}).$mount('#app')

ここではelは渡されないので、ソースコード

ここに画像の説明を挿入

絶対に去りません。ただし、新しい Vue を作成する場合、ユーザーは新しく作成された Vue インスタンスを使用して $mount を呼び出すことができます。このように、弊社の公式ウェブサイト上のライフサイクル図を理解しやすくなるかもしれません。

ここに画像の説明を挿入

さて、次に進みましょう。次のステップは$mountを実行することです。$mountメソッドを見てみましょう

2.3、$mount関数

以前初期化したときに $mount を上書きしたことを覚えていますか? そのため、今 $mount を実行すると、上書きされたマウントが実行されます。

ここに画像の説明を挿入

ここでは、書き換え前に書き換え前のマウントメソッドを保存し、最後に書き換え前のマウントメソッドを呼び出します。
書き直した後、最も重要なコードはレンダリング関数があるかどうかを判断することです

ここに画像の説明を挿入

このステップの主な機能は、レンダリング機能があるかどうかを判断することです。
はいの場合は、書き換えられた $mount メソッドの前にレンダリング関数を直接実行します。

そうでない場合は、まずテンプレートがあるかどうか (options.template が存在するかどうか、options.template は id セレクターまたは dom である可能性があるかどうか) を判断します。テンプレートが存在する場合は、テンプレート内のコンテンツが取得され、テンプレートに割り当てられます。options.template が存在しない場合は、el で指定された dom がテンプレートとして使用され (つまり #app)、el の下の dom が取得され、テンプレートに割り当てられます。

テンプレートがDOMを取得した後、テンプレートをレンダリング関数にコンパイルし、コンパイルされたレンダリング関数をoptions.render属性の下にマウントします。

ここに画像の説明を挿入

その後、書き換え前に $mount の実行を継続します。これを理解すると、ライフサイクル図の他の部分を理解できます。

ここに画像の説明を挿入

2.4、マウント前

次に、書き換え前の$mount関数の実行を見てみましょう。

ここに画像の説明を挿入

\$mountは主に関数mountComponentを実行していることがわかります。mountComponent関数を続けて見てみましょう。

ここに画像の説明を挿入

この関数は主に以下の 4 つのことを行うことがわかります。1 つずつ見ていきましょう。
1. beforeMount フックが実行されるので、beforeMount の前に、主にレンダリング関数を初期化して取得することがわかります。 beforeMount の後、レンダリング関数は仮想 DOM にレンダリングされ、その後実際の DOM が更新されます。
レンダリング関数を取得する方法は 3 つあります<br /> 1 つ目は、ユーザーがレンダリング関数に渡す方法です

ここに画像の説明を挿入

2番目: .vueファイルはレンダリングにコンパイルされます

ここに画像の説明を挿入

この方法では、レンダリング関数が渡され、関数内で h 関数が使用される前に App.vue ファイルが実行されます。
.vueファイルは最終的にvue-loaderの助けを借りてレンダリング関数に変換されます。

3番目に、テンプレートをレンダリング関数にコンパイルします。

ここに画像の説明を挿入
2. vm_update メソッドを呼び出して vm._render() メソッドを実行する updateComponent 関数を定義します。

操作後の結果は、_update メソッドにパラメータとして渡されます。前に述べたように、_render メソッドはレンダリング関数を内部的に仮想 DOM にレンダリングするため、_render() の戻り値は vnode になります。

まず、_render() 関数内でレンダリング関数が仮想 DOM に変換される方法を見てみましょう。

ここに画像の説明を挿入

それでは、_update関数内で何が行われているかを見てみましょう。

ここに画像の説明を挿入

_update 関数では、__patch__ メソッドが実行され、新しい DOM と古い DOM の 2 つが比較され、違いが発見されて実際の DOM が更新されていることがわかります。最初のレンダリングの場合は、現在の vnode が直接使用され、実際の DOM が生成されます。

したがって、updateComponent メソッド全体の主な機能は、レンダリング関数をレンダリングして DOM を更新することであると結論付けられます。
DOM を更新するための鍵は、updateComponent 関数をいつ呼び出すかにあります。

3. 新しいウォッチャーインスタンスを作成する

ここに画像の説明を挿入

新しいウォッチャー インスタンスが作成されると、updateComponent 関数がパラメーターとして渡されることがわかります。
この時点で、新しい Watcher を見ると、Watcher コンストラクターが実行されます。Watcher コンストラクターで何が行われるかを見てみましょう。

ここに画像の説明を挿入

ウォッチャーには、レンダリング ウォッチャー、$watch 関数ウォッチャー、計算ウォッチャーの 3 種類があります。ここでレンダリングするページはレンダリングウォッチャーです

上記では、渡した関数をゲッターに渡しています

ここに画像の説明を挿入

下に行くとget()が呼び出されます

ここに画像の説明を挿入

get() は渡した関数を呼び出し、渡した関数はレンダリング関数であり、仮想 DOM をトリガーして実際の DOM を更新し、返された値はレンダリング後の実際の DOM であり、最終的に this.value に割り当てられ、依存関係を更新するために使用されることがわかります。現在の天気インスタンスはメインの vue インスタンスのウォッチャーなので、ページ全体のウォッチャーとして理解できます。 this.$fouceUpdate() を呼び出すと、このインスタンスの update メソッドが呼び出され、ページ全体が更新されます。
したがって、新しい Wacher が作成されると、updateComponent が自動的に 1 回呼び出され、これが最初のレンダリングになります。

さて、下を見続けましょう

ここに画像の説明を挿入

内部的には、vm._isMounted が true (つまり、Mounted フックが実行された) であり、vm._isDestroyed が false (つまり、現在のコンポーネントが破棄されていない) であるかどうかが判断されます。この時点で更新が発生した場合、最初のレンダリングではないことを意味するため、beforeUpdate フックが実行され、後で必ず updated が実行されます。ここではアップデートについては話しません。

新しいウォッチャーの後もコードはダウンし続ける

ここに画像の説明を挿入

現在の vnode が null の場合、仮想 DOM が以前に生成されていないことを意味し、これは間違いなく最初のレンダリングであることを意味します。この時点で、vm._isMounted は true に設定されています。そしてマウントされたフック関数を実行すると、この時点で最初のレンダリングが完了します。

2.5、マウント

マウント前からマウントまでの全プロセスで行われる主な作業は、
1. レンダリング関数は仮想DOM vnodeになる
2. vm._update関数を実行して仮想DOMを実際のDOMに変換する
beforeUpdate フックと updated フックの間にある場合、最初のレンダリングではないことを意味し、仮想 DOM には古いものと新しいものの 2 つが含まれます。このとき、vm._update関数の役割は、古いvnodeと新しいvnodeを比較し、違いを見つけ、更新が必要なものを更新することです。

これが最初のレンダリングの全体のプロセスです。 Vue の初回レンダリングの全プロセスに関するこの記事はこれで終わりです。Vue の初回レンダリングに関するより関連性の高いコンテンツについては、123WORDPRESS.COM の過去の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • Vueコンポーネントのサーバー側レンダリングプロセスの詳細な説明
  • Vueレンダリングプロセスの簡単な分析
  • Vueソースコードの最初のレンダリング処理の詳細説明

<<:  データベース復旧エラーの原因となる MySQL 文字セットの簡単な分析

>>:  Nginx10m+の高並列カーネル最適化に関する簡単な説明

推薦する

HTML テーブル マークアップ チュートリアル (1): テーブルの作成

<br />これは 123WORDPRESS.COM が提供する一連のチュートリアルです...

PrometheusはGrafanaディスプレイを使用してMySQLを監視します

目次Prometheusはエクスポーターを介してMySQLを監視し、Grafanaチャートで表示しま...

MySQLの挿入文字化け問題を解決する方法

問題の説明: MySQL に中国語の文字を挿入する場合、または MySQL では中国語の文字が正常に...

docker CMD/ENTRYPOINT が sh スクリプトを実行する問題の解決策: not found/run.sh:

Dockerfile の設定に問題はありませんが、ENTRYPOINT コマンドを実行するとエラー...

docker で nginx+php+mysql を設定する方法

まず、方法を理解します。 docker exec を使用して Docker コンテナに入るDocke...

Echarts 基本入門: 棒グラフと折れ線グラフの一般的な構成

1eChartsの基本手順4つのステップ1 DOMコンテナを見つける2 初期化3 設定オプション4 ...

Docker ファイルの保存パス、コンテナの起動コマンド操作の取得

コンテナはすでに作成されていますが、その起動パラメータ(データがマウントされる場所)を知る方法 #コ...

Webpack3+React16コード分割の実装

プロジェクトの背景最近、webpackのバージョンが古いプロジェクトがあります。 リーダー層では今の...

Nodejs は JSON 文字列を JSON オブジェクトに変換するエラー解決法

JSON 文字列を JSON オブジェクトに変換するにはどうすればいいですか? JSON.parse...

Workbench を介して MySQL データベースにリモートでアクセスする方法の詳細な説明

序文Workbench が 1 台のコンピューターにインストールされており、別の Ubuntu サー...

DockerにTensorFlow環境を素早くインストールする方法

Docker に TensorFlow 環境をすばやくインストールし、TensorFlow を使用し...

Dockerボリュームのファイルマッピング方法

背景ブロックチェーン ログ モジュールで作業しているときに、コンテナーが実行されている場合は、ログ ...

JSはフロントエンドのページング効果を実現します

この記事の例では、フロントエンドのページング効果を実現するためのJSの具体的なコードを参考までに共有...

JavaScript と JQuery フレームワークの基本チュートリアル

目次1. JS オブジェクトDOM –1、機能–2、テスト3. jQuery –1. 概要–2、使用...

js で下線とキャメルケースの変換を実装する (複数の方法)

目次適用シナリオ:方法 1: 正規表現 (推奨)方法2: 配列のreduceメソッドを使用する方法3...