目次
#1 に直接移動できます。グローバル変数
flushCallbacksコールバックをトラバースして各 cb
nextTick の非同期実装 実行環境のサポートの程度に応じて、さまざまな非同期実装戦略を採用する
cbPromise
Vue のコンポーネント化とディストリビューションのアップデートについて学んでから戻ってきてください~
ホームページ ウェブフロントエンド Vue.js Vue の Vue.nextTick を理解するのに役立つ情報を共有する

Vue の Vue.nextTick を理解するのに役立つ情報を共有する

Mar 22, 2022 am 11:37 AM
vue

この記事では、Vueのピュアな辛口情報と、あなたの知らないVue.nextTickについてご紹介します。

Vue の Vue.nextTick を理解するのに役立つ情報を共有する

Vue を使用したことのある友人は多かれ少なかれそれを知っているでしょう$nextTick~ nextTick を正式に説明する前に、Vue について明確に理解しておく必要があると思います。 DOM を更新するときは、非同期で実行されます。次の説明プロセスはコンポーネントの更新と一緒に説明します~ 早速、本題に入りましょう (この記事では v2.0 を使用します)。 6.14 バージョンの Vue ソース コードを説明します) [関連する推奨事項: vuejs ビデオ チュートリアル ]

1. NextTick クイズ

NextTick を本当に理解していますか?さあ、直接質問に行きましょう~

<template>
  <div id="app">
    <p ref="name">{{ name }}</p>
    <button @click="handleClick">修改name</button>
  </div>
</template>

<script>
  export default {
  name: &#39;App&#39;,
  data () {
    return {
      name: &#39;井柏然&#39;
    }
  },
  mounted() {
    console.log(&#39;mounted&#39;, this.$refs.name.innerText)
  },
  methods: {
    handleClick () {
      this.$nextTick(() => console.log(&#39;nextTick1&#39;, this.$refs.name.innerText))
      this.name = &#39;jngboran&#39;
      console.log(&#39;sync log&#39;, this.$refs.name.innerText)
      this.$nextTick(() => console.log(&#39;nextTick2&#39;, this.$refs.name.innerText))
    }
  }
}
</script>
ログイン後にコピー

上記のコードでは、

が「名前の変更」ボタン をクリックすると、'nextTick1', '同期ログ' 'nextTick2' に対応する this.$refs.name.innerText がそれぞれ出力されますか? 、ここに出力されるのはDOMのinnerTextです~(答えは記事の最後に掲載されます)

現時点で明確な答えがある場合は、読み続ける必要はありません。わかりました~でも、答えに不安がある場合は、私に従って読み続けてください。読めば答えを見なくても明確な答えがわかると思いますよ~!


2. NextTick ソース コードの実装

ソース コードは core/util/next-tick にあります。これは 4 つの部分に分割でき、コード

#1 に直接移動できます。グローバル変数

##callbacks

Queue, pending Status<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'>const callbacks = [] // 存放cb的队列 let pending = false // 是否马上遍历队列,执行cb的标志</pre><div class="contentsignin">ログイン後にコピー</div></div>


2.

flushCallbacksコールバックをトラバースして各 cb

function flushCallbacks () {
  pending = false // 注意这里,一旦执行,pending马上被重置为false
  const copies = callbacks.slice(0)
  callbacks.length = 0
  for (let i = 0; i < copies.length; i++) {
    copies[i]() // 执行每个cb
  }
}
ログイン後にコピー


3.

nextTick の非同期実装 実行環境のサポートの程度に応じて、さまざまな非同期実装戦略を採用する

let timerFunc // nextTick异步实现fn

if (typeof Promise !== &#39;undefined&#39; && isNative(Promise)) {
  // Promise方案
  const p = Promise.resolve()
  timerFunc = () => {
    p.then(flushCallbacks) // 将flushCallbacks包装进Promise.then中
  }
  isUsingMicroTask = true
} else if (!isIE && typeof MutationObserver !== &#39;undefined&#39; && (
  isNative(MutationObserver) ||
  MutationObserver.toString() === &#39;[object MutationObserverConstructor]&#39;
)) {
  // MutationObserver方案
  let counter = 1
  const observer = new MutationObserver(flushCallbacks) // 将flushCallbacks作为观测变化的cb
  const textNode = document.createTextNode(String(counter)) // 创建文本节点
  // 观测文本节点变化
  observer.observe(textNode, {
    characterData: true
  })
  // timerFunc改变文本节点的data,以触发观测的回调flushCallbacks
  timerFunc = () => { 
    counter = (counter + 1) % 2
    textNode.data = String(counter)
  }
  isUsingMicroTask = true
} else if (typeof setImmediate !== &#39;undefined&#39; && isNative(setImmediate)) {
  // setImmediate方案
  timerFunc = () => {
    setImmediate(flushCallbacks)
  }
} else {
  // 最终降级方案setTimeout
  timerFunc = () => {
    setTimeout(flushCallbacks, 0)
  }
}
ログイン後にコピー

実際のこの事例は、
    MutationObserver
  • についての理解を深めます。結局のところ、他の 3 つの非同期ソリューションと比較すると、これは誰にとっても最も馴染みのないものになるはずです。
  • script start
    • script end

      はマクロ タスクの最初のラウンドで実行されますが、これは問題ありません

      setTimeout
    • はマクロ タスク実行の次のラウンドに置かれます
    • #MutationObserver
    • はマイクロ タスクであるため、次のようになりますマクロ タスクの現在のラウンドが実行された後に実行されるため、前に実行されます。
    • setTimeout

      結果は以下のようになります。

  • Vue の Vue.nextTick を理解するのに役立つ情報を共有する#4.
  • nextTick
メソッドの実装

cbPromise

メソッド

const observer = new MutationObserver(() => console.log(&#39;观测到文本节点变化&#39;))
const textNode = document.createTextNode(String(1))
observer.observe(textNode, {
    characterData: true
})

console.log(&#39;script start&#39;)
setTimeout(() => console.log(&#39;timeout1&#39;))
textNode.data = String(2) // 这里对文本节点进行值的修改
console.log(&#39;script end&#39;)
ログイン後にコピー
詳細については、pending が何に使用され、どのように機能するかを理解していますか?

  • ケース 1、Tick の同じラウンドで 2 回実行されます $nextTick
  • timerFunc
は 1 回だけ実行されます

<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'>export function nextTick (cb?: Function, ctx?: Object) { let _resolve // 往全局的callbacks队列中添加cb callbacks.push(() =&gt; { if (cb) { try { cb.call(ctx) } catch (e) { handleError(e, ctx, &amp;#39;nextTick&amp;#39;) } } else if (_resolve) { // 这里是支持Promise的写法 _resolve(ctx) } }) if (!pending) { pending = true // 执行timerFunc,在下一个Tick中执行callbacks中的所有cb timerFunc() } // 对Promise的实现,这也是我们使用时可以写成nextTick.then的原因 if (!cb &amp;&amp; typeof Promise !== &amp;#39;undefined&amp;#39;) { return new Promise(resolve =&gt; { _resolve = resolve }) } }</pre><div class="contentsignin">ログイン後にコピー</div></div> 画像を使用した方が直感的ですか?

  • #3. Vue コンポーネントの非同期更新

Vue のコンポーネント化がある場合は Vue の Vue.nextTick を理解するのに役立つ情報を共有する# # ディストリビューションのアップデート

あまり詳しくない方は、
ここをクリックして Vue の応答性の原理を図解でご覧ください

Vue のコンポーネント化とディストリビューションのアップデートについて学んでから戻ってきてください~

Vue の 非同期更新DOM は、実際には nextTick を使用して実装されます。これは、実際には通常使用する $nextTick と同じです~ここで、何が起こるかを確認します。属性の値を変更するとき?

上図のディストリビューション更新プロセスに従って、watcher.update の先頭から開始し、例として Rendering Watcher

を取り上げ、

queueWatcher

Vue の Vue.nextTick を理解するのに役立つ情報を共有する

1 と入力します。

queueWatcher は何をしましたか? <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'>this.$nextTick(() =&gt; console.log(&amp;#39;nextTick1&amp;#39;)) this.$nextTick(() =&gt; console.log(&amp;#39;nextTick2&amp;#39;))</pre><div class="contentsignin">ログイン後にコピー</div></div>

2.

flushSchedulerQueue は何をしましたか?
// 用来存放Wathcer的队列。注意,不要跟nextTick的callbacks搞混了,都是队列,但用处不同~
const queue: Array<Watcher> = []

function queueWatcher (watcher: Watcher) {
  const id = watcher.id // 拿到Wathcer的id,这个id每个watcher都有且全局唯一
  if (has[id] == null) {
    // 避免添加重复wathcer,这也是异步渲染的优化做法
    has[id] = true
    if (!flushing) {
      queue.push(watcher)
    }
    if (!waiting) {
      waiting = true
      // 这里把flushSchedulerQueue推进nextTick的callbacks队列中
      nextTick(flushSchedulerQueue)
    }
  }
}
ログイン後にコピー

最後に、コンポーネントの非同期更新プロセスを理解するための図

    4. 回帰の質問I
  • nextTick ソース コードの上記の分析を通じて、その謎のベールが明らかになったと考えています。このとき、答えをしっかりと伝えることができなければなりませんので、早速、自分の考えと合っているか、一緒に確認してみましょう!

1、如图所示,mounted时候的innerText是“井柏然”的中文

Vue の Vue.nextTick を理解するのに役立つ情報を共有する

2、接下来是点击按钮后,打印结果如图所示

Vue の Vue.nextTick を理解するのに役立つ情報を共有する

  • 没错,输出结果如下(意不意外?惊不惊喜?)

    • sync log 井柏然

    • nextTick1 井柏然

    • nextTick2 jngboran

  • 下面简单分析一下每个输出:

    this.$nextTick(() => console.log(&#39;nextTick1&#39;, this.$refs.name.innerText))
    this.name = &#39;jngboran&#39;
    console.log(&#39;sync log&#39;, this.$refs.name.innerText)
    this.$nextTick(() => console.log(&#39;nextTick2&#39;, this.$refs.name.innerText))
    ログイン後にコピー

    • sync log:这个同步打印没什么好说了,相信大部分童鞋的疑问点都不在这里。如果不清楚的童鞋可以先回顾一下EventLoop,这里不多赘述了~

    • nextTick1:注意其虽然是放在$nextTick的回调中,在下一个tick执行,但是他的位置是在this.name = 'jngboran'的前。也就是说,他的cb会App组件的派发更新(flushSchedulerQueue)更先进入队列,当nextTick1打印时,App组件还未派发更新,所以拿到的还是旧的DOM值。

    • nextTick2就不展开了,大家可以自行分析一下。相信大家对它应该是最肯定的,我们平时不就是这样拿到更新后的DOM吗?

  • 最后来一张图加深理解

  • Vue の Vue.nextTick を理解するのに役立つ情報を共有する


    写在最后,nextTick其实在Vue中也算是比较核心的一个东西了。因为贯穿整个Vue应用的组件化、响应式的派发更新与其息息相关~深入理解nextTick的背后实现原理,不仅能让你在面试的时候一展风采,更能让你在日常开发工作中,少走弯路少踩坑!好了,本文到这里就暂告一段落了,如果读完能让你有所收获,就帮忙点个赞吧~画图不易、创作艰辛鸭~

    (学习视频分享:vuejs教程web前端

    以上がVue の Vue.nextTick を理解するのに役立つ情報を共有するの詳細内容です。詳細については、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衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

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

SublimeText3 中国語版

SublimeText3 中国語版

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

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

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

VueでBootstrapの使用方法 VueでBootstrapの使用方法 Apr 07, 2025 pm 11:33 PM

vue.jsでBootstrapを使用すると、5つのステップに分かれています。ブートストラップをインストールします。 main.jsにブートストラップをインポートしますブートストラップコンポーネントをテンプレートで直接使用します。オプション:カスタムスタイル。オプション:プラグインを使用します。

VUEのボタンに関数を追加する方法 VUEのボタンに関数を追加する方法 Apr 08, 2025 am 08:51 AM

HTMLテンプレートのボタンをメソッドにバインドすることにより、VUEボタンに関数を追加できます。 VUEインスタンスでメソッドを定義し、関数ロジックを書き込みます。

vue.jsでJSファイルを参照する方法 vue.jsでJSファイルを参照する方法 Apr 07, 2025 pm 11:27 PM

vue.jsでJSファイルを参照するには3つの方法があります。タグ;; mounted()ライフサイクルフックを使用した動的インポート。 Vuex State Management Libraryを介してインポートします。

VueでWatchの使用方法 VueでWatchの使用方法 Apr 07, 2025 pm 11:36 PM

Vue.jsの監視オプションにより、開発者は特定のデータの変更をリッスンできます。データが変更されたら、Watchはコールバック関数をトリガーして更新ビューまたはその他のタスクを実行します。その構成オプションには、すぐにコールバックを実行するかどうかを指定する即時と、オブジェクトまたは配列の変更を再帰的に聴くかどうかを指定するDEEPが含まれます。

Vue Multi-Page開発とはどういう意味ですか? Vue Multi-Page開発とはどういう意味ですか? Apr 07, 2025 pm 11:57 PM

VUEマルチページ開発は、VUE.JSフレームワークを使用してアプリケーションを構築する方法です。アプリケーションは別々のページに分割されます。コードメンテナンス:アプリケーションを複数のページに分割すると、コードの管理とメンテナンスが容易になります。モジュール性:各ページは、簡単に再利用および交換するための別のモジュールとして使用できます。簡単なルーティング:ページ間のナビゲーションは、単純なルーティング構成を介して管理できます。 SEOの最適化:各ページには独自のURLがあり、SEOに役立ちます。

Vueによる前のページに戻る方法 Vueによる前のページに戻る方法 Apr 07, 2025 pm 11:30 PM

vue.jsには、前のページに戻る4つの方法があります。$ router.go(-1)$ router.back()outes&lt; router-link to =&quot;/&quot; Component Window.history.back()、およびメソッド選択はシーンに依存します。

VUEトラバーサルの使用方法 VUEトラバーサルの使用方法 Apr 07, 2025 pm 11:48 PM

Vue.jsには配列とオブジェクトを通過するには3つの一般的な方法があります。V-Forディレクティブは、各要素をトラバースしてテンプレートをレンダリングするために使用されます。 V-BindディレクティブをV-Forで使用して、各要素の属性値を動的に設定できます。 .mapメソッドは、配列要素を新しい配列に変換できます。

Vueにタグをジャンプする方法 Vueにタグをジャンプする方法 Apr 08, 2025 am 09:24 AM

VUEでタグのジャンプを実装する方法には、HTMLテンプレートでAタグを使用してHREF属性を指定する方法が含まれます。 VUEルーティングのルーターリンクコンポーネントを使用します。 JavaScriptでこれを使用します。$ router.push()メソッド。パラメーターはクエリパラメーターに渡すことができ、ルートは動的ジャンプのルーターオプションで構成されています。

See all articles