Maison >interface Web >Voir.js >Quel est le principe de réactivité de Vue ?

Quel est le principe de réactivité de Vue ?

醉折花枝作酒筹
醉折花枝作酒筹avant
2021-07-29 17:42:193060parcourir

J'ai lu récemment de nombreux articles sur les principes de Vue. Avec l'aide de ces articles, j'ai essayé à plusieurs reprises de comprendre moi-même le code source de Vue. Enfin, je pense qu'il est temps de publier le contenu moi-même. J'espère pouvoir familiariser tout le monde avec Vue sous un angle différent de celui des autres articles. La signification de

Quel est le principe de réactivité de Vue ?

Dep

var Dep = function Dep() {
  this.id = uid++
  this.subs = []
}

Dep est naturellement dépendance (c'est-à-dire dépendance, un nom dans le domaine informatique).

Tout comme l'écriture d'un programme node.js, les dépendances de l'entrepôt npm sont souvent utilisées. Dans Vue, les dépendances font spécifiquement référence aux données traitées de manière réactive. Comme nous le mentionnerons plus tard, l'une des fonctions clés du traitement réactif est DefineReactive, qui est mentionnée dans de nombreux articles sur les principes de Vue. Une fois que

Dep est lié à chaque donnée réactive, les données réactives deviendront une dépendance (nom). Lors de l'introduction de Watcher ci-dessous, il sera mentionné que les données réactives peuvent être surveillées, calculées ou utilisées dans des modèles depend (verbe).

subs

Dep Il y a un attribut subs sous l'objet, qui est un tableau. Il est facile de deviner qu'il s'agit de la liste des abonnés. Les abonnés peuvent surveiller des fonctions, des fonctions calculées ou visualiser des fonctions de mise à jour.

Watcher

Watcher est l'abonné mentionné dans Dep (à ne pas confondre avec l'observateur Observer plus tard).

Parce que la fonction de Watcher est de répondre aux mises à jour de Dep en temps opportun, tout comme la poussée d'abonnement de certaines applications. Si vous (Watcher) vous abonnez à certaines informations (Dep), il vous sera rappelé de les lire lorsque les informations sont disponibles. mis à jour.

deps

Semblable à Dep ayant l'attribut subs, l'objet Watcher a également l'attribut deps. Cela constitue une relation plusieurs-à-plusieurs entre Watcher et Dep. La raison de l'enregistrement mutuel est que lorsqu'une partie est autorisée, les objets associés peuvent être mis à jour dans le temps.

Watcher Comment générer

Les modèles de surveillance, de calcul et de rendu mentionnés à plusieurs reprises ci-dessus génèrent Watcher, qui est concis et facile à comprendre dans le code source de Vue :

  • vm._watcher de mountComponent = new Watcher(vm , updateComponent, noop) ; Observer
  • Observer est un observateur chargé d'observer (ou de traiter) de manière récursive des objets (ou tableaux) réactifs. Dans l'exemple imprimé, vous pouvez remarquer que les objets réactifs auront un __ob__, ce qui est la preuve de ce qui a été observé. Les observateurs ne sont pas aussi importants que Dep et Watcher ci-dessus, juste un peu de compréhension suffit.
  • walk

Observer.prototype.walk est la méthode principale du traitement récursif lorsque Observer est initialisé, mais cette méthode est utilisée pour traiter des objets, et il existe également Observer.prototype.observeArray pour traiter les tableaux.

Processus principal

Selon la relation entre les concepts ci-dessus, comment les faire correspondre et comment obtenir une mise à jour réactive des données ?

Définissons d'abord notre objectif : naturellement, lorsque les données sont mises à jour, la vue sera automatiquement actualisée pour afficher les dernières données.

C'est la relation entre Dep et Watcher mentionnée ci-dessus. Les données sont Dep, et Watcher déclenche la fonction de rendu de page (c'est l'observateur le plus important).

Mais une nouvelle question se pose : comment Dep sait-il que des Watchers dépendent de lui ?

Vue adopte une méthode très intéressante :

Avant d'exécuter la fonction de rappel du Watcher, notez d'abord ce qu'est le Watcher actuel (via Dep.target)

Les données réactives sont utilisées pour exécuter la fonction de rappel. La fonction getter des données réactives sera inévitablement appelée
  • Dans la fonction getter des données réactives, le Watcher actuel peut être enregistré et la relation entre Dep et Watcher sera établie
  • Après cela, lorsque le réactif les données sont mises à jour, cela sera inévitablement La fonction setter qui appellera les données réactives
  • Sur la base de la relation précédemment établie, la fonction de rappel correspondant au Watcher peut être déclenchée dans la fonction setter
  • Code
  • Ce qui précède la logique est dans la fonction DefineReactive. Il existe de nombreuses entrées pour cette fonction. Parlons d’abord de la fonction d’observation la plus importante.

    Dans la fonction observer, un nouvel objet Observer est créé, dans lequel Observer.prototype.walk est utilisé pour traiter les valeurs de l'objet une par une de manière réactive, et la fonction définirReactive est utilisée.
Parce que la fonction définirReactive est si importante et pas longue, il est plus pratique de la publier directement ici.

function defineReactive(obj, key, val, customSetter, shallow) {
  var dep = new Dep()
  depsArray.push({ dep, obj, key })
  var property = Object.getOwnPropertyDescriptor(obj, key)
  if (property && property.configurable === false) {
    return
  }

  // cater for pre-defined getter/setters
  var getter = property && property.get
  var setter = property && property.set

  var childOb = !shallow && observe(val)
  Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true,
    get: function reactiveGetter() {
      var value = getter ? getter.call(obj) : val
      if (Dep.target) {
        dep.depend()
        if (childOb) {
          childOb.dep.depend()
          if (Array.isArray(value)) {
            dependArray(value)
          }
        }
      }
      return value
    },
    set: function reactiveSetter(newVal) {
      var value = getter ? getter.call(obj) : val
      // 后半部分诡异的条件是用于判断新旧值都是 NaN 的情况
      if (newVal === value || (newVal !== newVal && value !== value)) {
        return
      }
      // customSetter 用于提醒你设置的值可能存在问题
      if ('development' !== 'production' && customSetter) {
        customSetter()
      }
      if (setter) {
        setter.call(obj, newVal)
      } else {
        val = newVal
      }
      childOb = !shallow && observe(newVal)
      dep.notify()
    },
  })
}

Tout d'abord, chaque valeur réactive est une "dépendance", donc dans la première étape, nous utilisons la capacité de fermeture pour créer un Dep pour chaque valeur. (Avec Vue 3, il n'y a pas besoin de fermetures)

Ensuite, regardez les trois paramètres principaux :

obj L'objet où la valeur doit actuellement être traitée de manière réactive

key La clé de la valeur
  • val Current La valeur de
  • peut avoir ses propres getter et setter définis auparavant, donc lors du traitement réactif de Vue, le getter et le setter d'origine doivent être traités en premier.
  • Comme mentionné ci-dessus dans le processus principal, la fonction getter établira la relation entre Dep et Watcher, en s'appuyant spécifiquement sur dep.depend().

    Vous trouverez ci-dessous plusieurs méthodes permettant à Dep et Watcher de s'appeler :
  • Dep.prototype.depend = function depend() {
      if (Dep.target) {
        Dep.target.addDep(this)
      }
    }
    Watcher.prototype.addDep = function addDep(dep) {
      var id = dep.id
      if (!this.newDepIds.has(id)) {
        this.newDepIds.add(id)
        this.newDeps.push(dep)
        if (!this.depIds.has(id)) {
          dep.addSub(this)
        }
      }
    }
    Dep.prototype.addSub = function addSub(sub) {
      this.subs.push(sub)
    }

    通过这几个函数,可以领略到了 Dep 和 Watcher 错综复杂的关系……不过看起来迂回,简单来说,其实做的就是上面说的互相添加到多对多列表。

    你可以在 Dep 的 subs 找到所有订阅同一个 Dep 的 Watcher,也可以在 Watcher 的 deps 找到所有该 Watcher 订阅的所有 Dep。

    但是里面还有一个隐藏问题,就是 Dep.target 怎么来呢?先放一放,后会作出解答。先接着看看 setter 函数,其中的关键是 dep.notify()。

    Dep.prototype.notify = function notify() {
      // stabilize the subscriber list first
      var subs = this.subs.slice()
      for (var i = 0, l = subs.length; i < l; i++) {
        subs[i].update()
      }
    }

    不难理解,就是 Dep 提醒他的订阅者列表(subs)里的所有人更新,所谓订阅者都是 Watcher,subs[i].update() 调用的也就是 Watcher.prototype.update。

    那么来看一下 Watcher 的 update 做了什么——

    Watcher.prototype.update = function update() {
      if (this.lazy) {
        this.dirty = true
      } else if (this.sync) {
        this.run()
      } else {
        queueWatcher(this)
      }
    }

    在这里我觉得有两个点比较值得展开,所以挖点坑

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer