Подробное объяснение жизненного цикла Vue + соответствующий анализ кода

JVM внешний интерфейс GitHub Vue.js

-Просмотр с GitHub

Для экземпляров Vue, таких как

const app = new Vue({...})

Когда браузер анализирует этот код, он автоматически выполняет метод монтирования beforeCreate => created => beforeMount => Всякий раз, когда изменяется значение свойства данных, например ==app.mes = "hi"==, он автоматически выполняется beforeUpdate => обновленный метод.

beforeCreate:

el     : undefined
data   : undefined
message: undefined

created:

el     : undefined
data   : [object Object]
message: hi

beforeMount:

el     : [object HTMLDivElement]
<div id="app"><p>{{ message }}</p></div>
data   : [object Object]
message: hi

mounted:

el     : [object HTMLDivElement]
<div id="app"><p>hi</p></div>
data   : [object Object]
message: hi

Когда вам нужно уничтожить этот экземпляр, вам нужно вручную выполнить app.$destroy(). Затем Vue автоматически вызовет методы beforeDestroy и destroy в это время.

Как только компонент будет уничтожен, он больше не будет реагировать, то есть изменить значение атрибута данных, например, app.mes="hello", страница не будет обновляться при этом, а данные на странице все равно будет показывать привет

В этом случае необходимость вручную звонить приложение $ CONTEL (), этот метод вызывается вручную, Vue автоматически выполняет следующие методы в следующем порядке: beforemount => foreupdate => обновлен => установлен.

На этом этапе мы обнаружим, что страница стала приветствовать Я так понимаю, что хотя приложение было уничтожено раньше, в атрибуте dep атрибута mes, отслеживая его наблюдателя, оно все равно становится «hello», но базовый компилятор (this.cb) не будет вызываться для рендеринга представления. И когда app.$mount() вызывается вручную, его метод компиляции активируется и снова становится отзывчивым. Когда мы вызываем метод destroy, мы фактически вызываем метод teardown для app._watcher, как показано в следующем коде (перед выполнением метода destroy мы вызываем функцию-ловушку callHook):

 Vue.prototype.$destroy = function () {
    var vm = this;
    if (vm._isBeingDestroyed) {
      return
    }
    callHook(vm, 'beforeDestroy');
    if (vm._watcher) {
      vm._watcher.teardown();
    }
    var i = vm._watchers.length;
    while (i--) {
      vm._watchers[i].teardown();
    }
}

Активному значению _watcher присваивается значение false, а затем вызывается removeSub, чтобы отменить подписку на всех подписчиков, от которых зависит наблюдатель (удаляются из массива subs каждого dep).

Watcher.prototype.teardown = function teardown () {
    var this$1 = this;

  if (this.active) {
    // remove self from vm's watcher list
    // this is a somewhat expensive operation so we skip it
    // if the vm is being destroyed.
    if (!this.vm._isBeingDestroyed) {
      remove(this.vm._watchers, this);
    }
    var i = this.deps.length;
    while (i--) {
      this$1.deps[i].removeSub(this$1);
    }
    this.active = false;
  }
};

Увидев это, мы знаем, что, несмотря на уничтожение, _watcher все еще остается тем же _watcher (на данный момент, если вызывается $mount, это не так). Что это значит? Другими словами, каждое значение свойства по-прежнему отслеживается в своем собственном наблюдателе. Однако, поскольку эти наблюдатели отписываются от депов, как только их значения будут изменены, обновление наблюдателя не будет вызываться (поскольку метод обновления каждого наблюдателя вызывается в уведомлении депа).

Когда мы видим, что вызывается обновление, на самом деле вызывается метод run, что означает, что реальное обновление (this.cb) действительно вызывается в run.

При запуске сначала оценивайте активность, если она ложна, представление не будет обновляться (больше не будет отвечать)

Watcher.prototype.update = function update () {
  /* istanbul ignore else */
  if (this.lazy) {
    this.dirty = true;
  } else if (this.sync) {
    this.run();
  } else {
    queueWatcher(this);
  }
};

//
Watcher.prototype.run = function run () {
  if (this.active) {
    var value = this.get();
    if (
      value !== this.value ||
      // Deep watchers and watchers on Object/Arrays should fire even
      // when the value is the same, because the value may
      // have mutated.
      isObject(value) ||
      this.deep
    ) {
      // set new value
      var oldValue = this.value;
      this.value = value;
      /..../
      {this.cb.call(this.vm, value, oldValue);
      }
    }
  }
};

Что ж, когда мы снова вызываем app.$mount(), мы фактически перекомпилируем узел в это время. Этот процесс прошел в этот момент: beforeMount => beforeUpdate => обновлено => смонтировано

Посмотрев исходный код, мы обнаружили, что в методе $mount вызывается метод compileToFunctions, а в методе compileToFunctions вызывается метод compile, то есть на данный момент мы пересоздали новый Watcher для свойство app.mes.

var mount = Vue.prototype.$mount;
Vue.prototype.$mount = function (el,
  hydrating){
  //.......
  var ref = compileToFunctions(template, {
        shouldDecodeNewlines: shouldDecodeNewlines,
        shouldDecodeNewlinesForHref: shouldDecodeNewlinesForHref,
        delimiters: options.delimiters,
        comments: options.comments
   }, this);
   //....
    
}
//...
function compileToFunctions(){
  //....
  var compiled = compile(template, options);
  //...
}

Если читатель сбит с толку приведенным выше анализом, мы можем проверить его:

Перед вызовом destroy мы сначала объявляем переменную p для хранения ссылки на объект-наблюдатель в это время (поскольку jvm решает, удалять ли этот объект из памяти в соответствии с удерживанием объекта. Таким образом, этот старый наблюдатель не будет удален)

// teardown之前
p=app._watcher.deps[0].subs[0];
// teardown之后,又调用$mount()
pp = app._watcher.deps[0].subs[0];

// 比较
p === pp //输出false,说明这个watcher是新new出来的

-Легко понять жизненный цикл -vue-instance/

-Путь исследования Vue2.0 — некоторое понимание жизненного цикла и функции крючка