Анализ процесса выполнения Vue

Vue.js внешний фреймворк
Анализ процесса выполнения Vue

введение

Я считаю, что большинство фронтенд-партнеров не могут вспомнить, сколько проектов они сделали и сколько кода они написали.Все пишут код Vue как учебник:

// 单文件组件中常见代码
export default {
  data () {
    return {
      msg: 'click me'
    }
  },
  methods: {
    say () {
      this.msg = 'well done'
    }
  }
}
// 入口文件中的常见代码
new Vue({
  el: '#app',
  router: router,
  render: h => h(App)
})

Все кажется таким естественным. Тем не менее, в напряженном графике кто-нибудь из ваших друзей когда-нибудь задумывался о том, как небольшой экземпляр Vue может иметь столько энергии для создания такого сложного внешнего проекта. Итак, как Vue работает внутри и что он делает?

Vue может работать на нескольких платформах, таких как браузеры, weex и т. д. В этой статье анализируется только основной процесс выполнения Vue в среде браузера.

инициализация

Давайте сначала посмотрим на конструктор Vue:

// Vue构造函数
function Vue (options) {
  if (process.env.NODE_ENV !== 'production' &&
    !(this instanceof Vue)
  ) {
    warn('Vue is a constructor and should be called with the `new` keyword')
  }
  // 执行初始化逻辑
  this._init(options)
}

Как видно из конструктора Vue, когда мы выполняемnew Vue(), единственный_initметод._initVue будет инициализирован в соответствии с переданными параметрами. В этом процессе завершается инициализация реквизита, данных, жизненного цикла и механизма событий.

Взяв за пример инициализацию данных, vue пройдетObject.definePropertyСпособ определения атрибутов данных для экземпляра vue. Это также объясняет, почему мы можем передатьthis.msgЧтобы назначить значение, вы можете изменить значение данных в данных.

Описанная выше обработка данных — это только начало. Чтобы реализовать так называемое адаптивное или управляемое данными обновление, vue провел дальнейшую обработку.Конкретный метод заключается в созданииobserverобъект, который привязан к данным, черезObject.definePropertyПреобразование всех атрибутов данных вgetter/setter. Когда свойства в данных доступны в экземпляре vue (будет запущен геттер),observerОбъект будет собирать свойство какwatcherЗависимости экземпляра, затем, когда свойства данных изменяются в экземпляре vue (установщик будет запущен),observerуведомит тех, кто зависит от этого свойстваwatcherЭкземпляр повторно отображает страницу.

Примечание. Каждый наблюдатель соответствует экземпляру vue.

Вышеуказанные потоки обработки связаны вместе, и Vue реализуется путем измененияthis.msgЭто запускает автоматическое обновление страницы.

Наконец, позаимствуйте схематическую диаграмму на официальном сайте Vue, чтобы помочь вам понять этот процесс:

Разбор шаблона

Благодаря приведенному выше анализу мы уже знаем, что при изменении данных страница будет перерисована. Далее давайте проанализируем, как vue отрисовывает.

Во-первых, vue проанализирует шаблон HTML, который мы написали, в объект описания AST, который передается черезchildrenа такжеparentСвязанная древовидная структура полностью описывает всю информацию тегов HTML.

Например, следующий HTML-шаблон:

<div id="app">
    <p>{{msg}}</p>
</div>

В конечном итоге он будет преобразован в объект AST следующего вида:

{
   attrs: [{name: "id", value: ""app"", dynamic: undefined, start: 5, end: 13}],
   attrsList: [{name: "id", value: "app", start: 5, end: 13}],
   attrsMap: {id: "app"},
   children: [{
        attrsList: [],
        attrsMap: {},
        children: [],
        end: 33,
        parent: {type: 1, tag: "div", ...},
        plain: true,
        pre: undefined,
        rawAttrsMap:{},
        start: 19
        tag: "p",
        type: 1
   }],
   end: 263,
   parent: undefined,
   plain: false,
   rawAttrsMap:{id: {name: "id", value: "app", start: 5, end: 13}},
   start: 0
   tag: "div",
   type: 1
}

потомvueОбъекты, сгенерированные ASTrenderфункция, тело функции функции примерно выглядит следующим образом:

with(this){
    return _c('div', {attrs:{"id":"app"}}, [_c('p', [_v(_s(msg))])])
}

То есть наш шаблон окажется внутри vue сrenderсуществует в виде функции.

Это также упоминается на официальном веб-сайте vue.Обычно рекомендуется использовать шаблон, el и т. д. для указания шаблонов. функция.

Реальность первая

у нас естьrenderПосле функции vue не выполняет рендеринг напрямую в DOM-дерево, а сначала передаетrenderфункция получаетvnode. На самом деле, этот шаг очень необходим, и все мы знаем, что частая работа с узлами DOM в больших количествах чрезвычайно требовательна к производительности. vue передает пару перед рендерингомvnodeСравнение может значительно избежать ненужных манипуляций с DOM. Ниже приведенvnodeГрубая структура:

{
    tag: "div",
    children: [{tag: "p", ...}],
    data: {attrs: {id: "app"}}
    elm: DOM节点(div#app),
    parent: undefined,
    context: Vue实例,
    ...
}

Наконец, Vue выполняет такие операции, как вставка, обновление и удаление реальных узлов DOM в соответствии с результатами после сравнения и запускает функцию ловушки жизненного цикла экземпляра Vue. После этого Vue должен наблюдать за изменениями в данных, а затем решать, следует ли повторно отображать страницу.

Суммировать

Вышеупомянутый основной процесс vue в начальном процессе рендеринга.Вообще говоря, это сначала инициализировать объект опции, а затем передатьObject.definePropertyСоздайте отзывчивую систему, а затем разберите шаблон наrenderфункцию, затем используйтеrenderФункция генерирует vnode перед рендерингом дляvnodeВыполните операцию diff и, наконец, выполните необходимый рендеринг.

В этой статье мы не будем вдаваться в подробности кода при каждом выполнении.Далее мы подробно расскажем об инициализации, принципе адаптивной реализации, рендеринге шаблонов, разборе инструкций, различиях vnode и т. д., так что следите за обновлениями.

Подписывайтесь на нас

公众号@前端论道