предисловие
Vue.js 2.0 представляет Virtual DOM, который в 2-4 раза быстрее начальной скорости рендеринга Vue.js 1.0 и значительно снижает потребление памяти. Итак, что такое виртуальный DOM? Зачем вам виртуальный DOM? Как это повышает эффективность рендеринга страницы? Именно об этом вопросе и пойдет речь в этой статье.
Процесс преобразования шаблона в представление
Прежде чем официально представить Virtual Dom, нам необходимо понять весь процесс преобразования шаблона в представление, как показано на следующем рисунке (см. «Введение в vue.js»):
- Vue.js преобразует шаблон шаблона в функцию рендеринга (рендеринга) путем компиляции, а выполнение функции рендеринга может получить виртуальное дерево узлов
- Когда модель работает, объект Watcher в соответствующем Dep будет активирован. Объект Watcher вызовет соответствующее обновление для изменения представления. Этот процесс в основном предназначен для сравнения разницы между старыми и новыми виртуальными узлами, а затем выполнения операций DOM для обновления представления в соответствии с результатом сравнения.
Проще говоря, в базовой реализации Vue Vue компилирует шаблоны в виртуальные функции рендеринга DOM. В сочетании с собственной системой ответов Vue Vue может интеллектуально рассчитать минимальную стоимость повторного рендеринга компонентов и применить ее к операциям DOM при изменении состояния.
- функция рендеринга: Функция рендеринга используется для создания виртуального DOM. Vue рекомендует использовать шаблоны для создания интерфейса нашего приложения. В базовой реализации Vue будет компилировать шаблоны в функции рендеринга. Конечно, мы также можем писать функции рендеринга напрямую, без написания шаблонов для лучшего контроля.
- Виртуальный узел VNode: он может представлять собой настоящий узел dom. VNode можно преобразовать в узел dom с помощью метода createElement. Проще говоря, vnode можно понимать какобъект описания узла, который описывает, как должны создаваться настоящие узлы DOM.
- патч (также называемый алгоритмом исправления): Основная часть виртуального DOM, он может преобразовать vnode в реальный DOM.Этот процесс заключается в сравнении различий между старыми и новыми виртуальными узлами, а затем нахождении узлов, которые необходимо обновить в соответствии с результатами сравнения. . Мы можем видеть из значения слова, что патч сам по себе имеет значение исправления и исправления, и его фактическая функция состоит в том, чтобы изменить существующий DOM для достижения цели обновления представления. Алгоритм Vue Virtual DOM Patching основан наSnabbdomреализации, и внес множество корректировок и улучшений в эти основы.
Что такое виртуальный DOM?
Виртуальный DOM на самом деле представляет собой дерево, основанное на объектах JavaScript (узлах VNode), и использует атрибуты объектов для описания узлов, фактически это просто абстракция реального DOM. Наконец, это дерево можно сопоставить с реальной средой с помощью ряда операций.
Короче говоря, Virtual DOM можно понимать как простой объект JS, и он содержит как минимум три атрибута: имя тега (tag), атрибут (attrs) и объект дочернего элемента (children). Различные фреймворки называют эти три свойства немного по-разному.
Для виртуального DOM рассмотрим простой пример, показанный на рисунке ниже, где подробно объясняется模板 → 渲染函数 → 虚拟DOM树 → 真实DOM
процесс
Какова роль виртуального DOM?
Конечная цель виртуального DOM — визуализировать виртуальные узлы в представлении.. Но если вы напрямую перезапишете старые узлы виртуальными узлами, будет много ненужных операций с DOM. Например, под тегом ul находится много тегов li, а изменился только один li. В этом случае, если вместо старого ul используется новый ul, производительность будет потеряна из-за этих ненужных операций DOM.
Чтобы избежать ненужных операций DOM, виртуальный DOM сравнивает виртуальный узел со старым виртуальным узлом (oldVnode), использовавшимся для рендеринга представления в последний раз в процессе сопоставления виртуального узла с представлением, и находит узел, который действительно нужен быть обновленным для работы DOM., что позволяет избежать манипулирования другими DOM, которые не нужно изменять.
На самом деле, виртуальный DOM в Vue.js в основном выполняет две функции:
- Укажите виртуальный узел vnode, соответствующий реальному узлу DOM.
- Сравните виртуальный узел vnode со старым виртуальным узлом oldVnode, затем обновите представление.
Зачем вам виртуальный DOM?
- Имеет преимущество кроссплатформенности
Поскольку виртуальный DOM основан на объектах JavaScript и не зависит от среды реальной платформы, он обладает кросс-платформенными возможностями, такими как платформы браузеров, Weex, Node и т. д.
- Медленно действует DOM, а JS эффективно работает. Мы можем поставить операцию сравнения DOM на слое JS для повышения эффективности.
Поскольку скорость выполнения DOM-операций намного меньше, чем у Javascript, большое количество DOM-операций переносится на Javascript, а алгоритм исправления используется для вычисления узлов, которые действительно нуждаются в обновлении, минимизируя DOM-операции, тем самым значительно улучшая представление.
Виртуальный DOM — это, по сути, кеш между JS и DOM. Это можно сравнить с процессором и жестким диском.Поскольку жесткий диск такой медленный, мы добавим кеш между ними: поскольку DOM такой медленный, мы добавим кеш между их JS и DOM. CPU (JS) работает только с памятью (Virtual DOM) и в конце записывает изменения на жесткий диск (DOM).
- Улучшить производительность рендеринга
Преимуществом Virtual DOM является не разовая операция, а разумное и эффективное обновление представления при большом количестве частых обновлений данных.
Для эффективного манипулирования DOM необходим эффективный алгоритм сравнения виртуальных DOM.Мы используем ядро алгоритма patch----diff, чтобы узнать, какие узлы нужно обновить в этом DOM для обновления, а остальные не обновляются.. Какова реализация алгоритма DIFF?
алгоритм сравнения
Алгоритм сравнения Vue основан на snabbdom.Различать только vnodes одного уровня, рекурсивно выполнять сравнение vnodes одного уровня и, наконец, обновлять все дерево DOM.. Поскольку операций в иерархии очень мало и ими можно пренебречь, временная сложность изменяется с O(n3) до O(n).
Алгоритм сравнения состоит из нескольких шагов:
- Используйте структуру объектов JavaScript для представления структуры дерева DOM, а затем используйте это дерево для построения настоящего дерева DOM и вставки его в документ.
- При изменении состояния реконструируется новое дерево объектов. Затем сравните новое дерево со старым деревом и запишите разницу между двумя деревьями.
- Примените записанные различия к построенному реальному дереву DOM, и представление обновится.
Процесс реализации алгоритма diff
Алгоритм diff сам по себе очень сложен и труден в реализации. В этой статье будет упрощено сложное и кратко представлены следующие два основных процесса реализации функций:
- patch(container,vnode) : при первом рендеринге виртуальный дом визуализируется в настоящий DOM и вставляется в контейнер.
- patch(vnode, newVnode): при повторном рендеринге сравните новый vnode со старым vnode, а затем примените разницу к построенному настоящему дереву DOM.
1.patch(container,vnode)
С помощью этой функции VNode может быть преобразован в настоящий DOM.Мы можем понять общий процесс с помощью следующего кода моделирования:
function createElement(vnode) {
var tag = vnode.tag
var attrs = vnode.attrs || {}
var children = vnode.children || []
if (!tag) {
return null
}
// 创建真实的 DOM 元素
var elem = document.createElement(tag)
// 属性
var attrName
for (attrName in attrs) {
if (attrs.hasOwnProperty(attrName)) {
// 给 elem 添加属性
elem.setAttribute(attrName, attrs[attrName])
}
}
// 子元素
children.forEach(function (childVnode) {
// 给 elem 添加子元素,如果还有子节点,则递归的生成子节点。
elem.appendChild(createElement(childVnode)) // 递归
}) // 返回真实的 DOM 元素
return elem
}
2.patch(vnode,newVnode)
Здесь мы рассматриваем только случай, когда vnode сравнивается с newVnode:
function updateChildren(vnode, newVnode) {
var children = vnode.children || []
var newChildren = newVnode.children || []
// 遍历现有的children
children.forEach(function (childVnode, index) {
var newChildVnode = newChildren[index]
// 两者tag一样
if (childVnode.tag === newChildVnode.tag) {
// 深层次对比,递归
updateChildren(childVnode, newChildVnode)
} else {
// 两者tag不一样
replaceNode(childVnode, newChildVnode)
}
}
)}
Порекомендуйте полезный инструмент мониторинга ошибок для всехFundebug, добро пожаловать, чтобы попробовать это бесплатно!
Добро пожаловать в публичный аккаунт:Мастер по фронтенду, мы будем свидетелями вашего роста вместе!
Справочные статьи и книги
- Архитектурный класс Everest (настоятельно рекомендуется)
- Анализ внутренней работы Vue.js
- Подробное объяснение Vue.js
- Примечания к изучению Vue 2.0: функция рендеринга Vue
- Демистификация продвинутого интервью с передовыми интернет-компаниями по интерфейсу JavaScript
- Некоторое понимание виртуального дома
- Глубокий анализ: как реализовать алгоритм виртуального DOM