Table des matières
一、nextTick小测试
二、nextTick源码实现
1. 全局变量
2. flushCallbacks
3. nextTick的异步实现
4. nextTick方法实现
三、Vue组件的异步更新
1. queueWatcher做了什么?
tutoriel vidéo vuejs】" >2. flushSchedulerQueue pour expliquer) [ Recommandations associées : tutoriel vidéo vuejs
Maison interface Web Voir.js Partager des informations utiles pour vous aider à comprendre Vue.nextTick dans Vue

Partager des informations utiles pour vous aider à comprendre Vue.nextTick dans Vue

Mar 22, 2022 am 11:37 AM
vue

Cet article partagera avec vous VueDes informations pures et vous présentera Vue.nextTick que vous ne connaissez pas. J'espère qu'il sera utile à tout le monde !

Partager des informations utiles pour vous aider à comprendre Vue.nextTick dans Vue

Les amis qui ont utilisé Vue connaissent plus ou moins $nextTick~ Avant d'expliquer formellement nextTick, je pense que vous devez clairement savoir que Vue est asynchrone lors de la mise à jour du DOM. code>, car le prochain processus d'explication sera expliqué avec les mises à jour des composants~ Sans plus tarder, passons directement au sujet (cet article utilise le code source Vue de la version v2.6.14$nextTick~ 在正式讲解nextTick之前,我想你应该清楚知道 Vue 在更新 DOM 时是异步执行的,因为接下来讲解过程会结合组件更新一起讲~ 事不宜迟,我们直进主题吧(本文以v2.6.14版本的Vue源码进行讲解)【相关推荐:vuejs视频教程

一、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>
Copier après la connexion

请问上述代码中,当点击按钮“修改name”时,&#39;nextTick1&#39;&#39;sync log&#39;&#39;nextTick2&#39;对应的this.$refs.name.innerText分别会输出什么?注意,这里打印的是DOM的innerText~(文章结尾处会贴出答案)

如果此时的你有非常坚定的答案,那你可以不用继续往下看了~但如果你对自己的答案有所顾虑,那不如跟着我,接着往下看。相信你看完,不需要看到答案都能有个肯定的答案了~!


二、nextTick源码实现

源码位于core/util/next-tick中。可以将其分为4个部分来看,直接上代码

1. 全局变量

callbacks队列、pending状态

const callbacks = [] // 存放cb的队列
let pending = false // 是否马上遍历队列,执行cb的标志
Copier après la connexion

2. flushCallbacks

遍历callbacks执行每个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
  }
}
Copier après la connexion

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)
  }
}
Copier après la connexion
  • 这里用个真实案例加深对MutationObserver的理解。毕竟比起其他三种异步方案,这个应该是大家最陌生的
    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;)
    Copier après la connexion
  • 知道对应的输出会是怎么样的吗?
    • script startscript end会在第一轮宏任务中执行,这点没问题

    • setTimeout会被放入下一轮宏任务执行

    • MutationObserver是微任务,所以会在本轮宏任务后执行,所以先于setTimeout

  • 结果如下图:
    Partager des informations utiles pour vous aider à comprendre Vue.nextTick dans Vue

4. nextTick方法实现

cbPromise方式

export function nextTick (cb?: Function, ctx?: Object) {
  let _resolve
  // 往全局的callbacks队列中添加cb
  callbacks.push(() => {
    if (cb) {
      try {
        cb.call(ctx)
      } catch (e) {
        handleError(e, ctx, &#39;nextTick&#39;)
      }
    } else if (_resolve) {
      // 这里是支持Promise的写法
      _resolve(ctx)
    }
  })
  if (!pending) {
    pending = true
    // 执行timerFunc,在下一个Tick中执行callbacks中的所有cb
    timerFunc()
  }
  // 对Promise的实现,这也是我们使用时可以写成nextTick.then的原因
  if (!cb && typeof Promise !== &#39;undefined&#39;) {
    return new Promise(resolve => {
      _resolve = resolve
    })
  }
}
Copier après la connexion
  • 深入细节,理解pending有什么用,如何运作?

案例1,同一轮Tick中执行2次$nextTicktimerFunc只会被执行一次

this.$nextTick(() => console.log(&#39;nextTick1&#39;))
this.$nextTick(() => console.log(&#39;nextTick2&#39;))
Copier après la connexion
  • 用图看看更直观?

Partager des informations utiles pour vous aider à comprendre Vue.nextTick dans Vue


三、Vue组件的异步更新

这里如果有对Vue组件化派发更新不是十分了解的朋友,可以先戳这里,看图解Vue响应式原理了解下Vue组件化和派发更新的相关内容再回来看噢~

Vue的异步更新DOM其实也是使用nextTick来实现的,跟我们平时使用的$nextTick其实是同一个~

这里我们回顾一下,当我们改变一个属性值的时候会发生什么?

Partager des informations utiles pour vous aider à comprendre Vue.nextTick dans Vue

根据上图派发更新过程,我们从watcher.update开时讲起,以渲染Watcher为例,进入到queueWatcher

1. queueWatcher做了什么?

// 用来存放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)
    }
  }
}
Copier après la connexion

2. flushSchedulerQueue pour expliquer) [ Recommandations associées : tutoriel vidéo vuejs

< h2 data-id=" head-0">1. Quiz NextTick
  • Comprenez-vous vraiment nextTick ? Allez, allez directement à la question~
  • function flushSchedulerQueue () {
      currentFlushTimestamp = getNow()
      flushing = true
      let watcher, id
      // 排序保证先父后子执行更新,保证userWatcher在渲染Watcher前
      queue.sort((a, b) => a.id - b.id)
      // 遍历所有的需要派发更新的Watcher执行更新
      for (index = 0; index < queue.length; index++) {
        watcher = queue[index]
        id = watcher.id
        has[id] = null
        // 真正执行派发更新,render -> update -> patch
        watcher.run()
      }
    }
    Copier après la connexion
Dans le code ci-dessus, quand cliquez sur le bouton

"Modifier le nom", 'nextTick1', 'sync log'</ code>, quelle sera la sortie <code>this.$refs.name.innerText correspondante de 'nextTick2' ? RemarquePartager des informations utiles pour vous aider à comprendre Vue.nextTick dans Vue, ce qui est imprimé ici est le texte interne du DOM~ (la réponse sera publiée à la fin de l'article)


Si vous avez une réponse très ferme à ce moment-là, alors vous n'avez pas besoin de continuez à lire ~ Mais si vous avez raison Si vous avez des inquiétudes concernant votre réponse, pourquoi ne pas me suivre et continuer à lire. Je crois qu'après l'avoir lu, vous aurez une réponse définitive sans avoir à voir la réponse ~ !

2. Implémentation du code source de NextTick

Le code source se trouve dans core/util/next-tick. Il peut être divisé en 4 parties et aller directement dans la file d'attente du code🎜

1 Variables globales🎜🎜🎜callbacks, en attente. status 🎜
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))
Copier après la connexion
Copier après la connexion
🎜

2. flushCallbacks🎜🎜🎜Traversez les rappels pour exécuter chaque cb🎜rrreee🎜

3. Implémentation asynchrone de nextTick🎜🎜🎜Adopter différentes stratégies d'implémentation asynchrone selon le niveau de support de l'environnement d'exécution🎜rrreee🎜🎜Voici un cas réel à approfondir la compréhension de MutationObserver. Après tout, comparée aux trois autres solutions asynchrones, celle-ci devrait être la moins familière à tout le monde. Savez-vous à quoi ressemblera le résultat correspondant ?

Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn

Outils d'IA chauds

Undresser.AI Undress

Undresser.AI Undress

Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover

AI Clothes Remover

Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool

Undress AI Tool

Images de déshabillage gratuites

Clothoff.io

Clothoff.io

Dissolvant de vêtements AI

Video Face Swap

Video Face Swap

Échangez les visages dans n'importe quelle vidéo sans effort grâce à notre outil d'échange de visage AI entièrement gratuit !

Outils chauds

Bloc-notes++7.3.1

Bloc-notes++7.3.1

Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise

SublimeText3 version chinoise

Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1

Envoyer Studio 13.0.1

Puissant environnement de développement intégré PHP

Dreamweaver CS6

Dreamweaver CS6

Outils de développement Web visuel

SublimeText3 version Mac

SublimeText3 version Mac

Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Comment utiliser Bootstrap en Vue Comment utiliser Bootstrap en Vue Apr 07, 2025 pm 11:33 PM

L'utilisation de bootstrap dans vue.js est divisée en cinq étapes: installer bootstrap. Importer un bootstrap dans main.js. Utilisez le composant bootstrap directement dans le modèle. Facultatif: style personnalisé. Facultatif: utilisez des plug-ins.

Comment ajouter des fonctions aux boutons pour Vue Comment ajouter des fonctions aux boutons pour Vue Apr 08, 2025 am 08:51 AM

Vous pouvez ajouter une fonction au bouton VUE en liant le bouton dans le modèle HTML à une méthode. Définissez la logique de la fonction de méthode et d'écriture dans l'instance Vue.

Comment référencer le fichier JS avec Vue.js Comment référencer le fichier JS avec Vue.js Apr 07, 2025 pm 11:27 PM

Il existe trois façons de se référer aux fichiers JS dans Vue.js: spécifiez directement le chemin à l'aide du & lt; script & gt; étiqueter;; importation dynamique à l'aide du crochet de cycle de vie monté (); et l'importation via la bibliothèque de gestion de l'État Vuex.

Comment utiliser Watch in Vue Comment utiliser Watch in Vue Apr 07, 2025 pm 11:36 PM

L'option Watch dans Vue.js permet aux développeurs d'écouter des modifications de données spécifiques. Lorsque les données changent, regardez déclenche une fonction de rappel pour effectuer des vues de mise à jour ou d'autres tâches. Ses options de configuration incluent immédiatement, qui spécifie s'il faut exécuter un rappel immédiatement, et profond, ce qui spécifie s'il faut écouter récursivement les modifications des objets ou des tableaux.

Que signifie le développement de plusieurs pages Vue? Que signifie le développement de plusieurs pages Vue? Apr 07, 2025 pm 11:57 PM

Le développement multi-pages VUE est un moyen de créer des applications à l'aide du cadre Vue.js, où l'application est divisée en pages distinctes: Maintenance du code: La division de l'application en plusieurs pages peut rendre le code plus facile à gérer et à maintenir. Modularité: chaque page peut être utilisée comme module séparé pour une réutilisation et un remplacement faciles. Routage simple: la navigation entre les pages peut être gérée par une configuration de routage simple. Optimisation du référencement: chaque page a sa propre URL, ce qui aide le référencement.

Comment revenir à la page précédente par Vue Comment revenir à la page précédente par Vue Apr 07, 2025 pm 11:30 PM

Vue.js dispose de quatre méthodes pour revenir à la page précédente: $ router.go (-1) $ router.back () utilise & lt; router-link to = & quot; / & quot; Composant Window.History.back (), et la sélection de la méthode dépend de la scène.

Comment utiliser Vue Traversal Comment utiliser Vue Traversal Apr 07, 2025 pm 11:48 PM

Il existe trois méthodes courantes pour que Vue.js traverse les tableaux et les objets: la directive V-FOR est utilisée pour traverser chaque élément et les modèles de rendu; La directive V-Bind peut être utilisée avec V-FOR pour définir dynamiquement les valeurs d'attribut pour chaque élément; et la méthode .map peut convertir les éléments du tableau en nouveaux tableaux.

Comment sauter une balise à Vue Comment sauter une balise à Vue Apr 08, 2025 am 09:24 AM

Les méthodes pour implémenter le saut d'une balise dans Vue incluent: l'utilisation de la balise A dans le modèle HTML pour spécifier l'attribut HREF. Utilisez le composant routeur-link du routage Vue. Utilisez cette méthode. $ Router.push () dans JavaScript. Les paramètres peuvent être passés à travers le paramètre de requête et les itinéraires sont configurés dans les options de routeur pour les sauts dynamiques.

See all articles