Представление VNode с помощью битов
Представление типов VNode с помощью битов
Существуют различные типы VNode. Например, на данный момент реализованы следующие:
- узел компонента
- узел элемента
- текстовый узел
- является ли дочерний элемент текстом или нет
- является ли дочерний элемент массивом или нет
И в будущем будут реализованы еще больше типов VNode. Например, slot, keep-alive, suspense, teleport и т.д.
В настоящее время ветвление выполняется с помощью условий типа type === Text
, typeof type === "string"
, typeof type === "object"
и т.д.
Проверка этих условий по одному неэффективна, поэтому давайте попробуем представить их с помощью битов, следуя реализации оригинала. В Vue эти биты называются "ShapeFlags". Как следует из названия, они представляют форму VNode. (Строго говоря, в Vue для определения типа VNode используются ShapeFlags и символы, такие как Text и Fragment.) https://github.com/vuejs/core/blob/main/packages/shared/src/shapeFlags.ts
Битовые флаги относятся к обработке каждого бита числа как определенного флага.
Рассмотрим следующий VNode в качестве примера:
const vnode = {
type: 'div',
children: [
{ type: 'p', children: ['hello'] },
{ type: 'p', children: ['hello'] },
],
}
Сначала начальное значение флага равно 0. (Для простоты это объяснение дается с использованием 8 битов.)
let shape = 0b0000_0000
Теперь этот VNode является элементом и имеет массив дочерних элементов, поэтому устанавливаются флаги ELEMENT и ARRAY_CHILDREN.
shape = shape | ShapeFlags.ELEMENT | ELEMENT.ARRAY_CHILDREN // 0x00010001
С помощью этого мы можем представить информацию о том, что этот VNode является элементом и имеет массив дочерних элементов, используя всего одно число, называемое "shape". Мы можем эффективно управлять типами VNode, используя это в ветвлении в рендерере или других частях кода.
if (vnode.shape & ShapeFlags.ELEMENT) {
// Обработка, когда vnode является элементом
}
Поскольку мы не реализуем все ShapeFlags в этот раз, попробуйте реализовать следующее в качестве упражнения:
export const enum ShapeFlags {
ELEMENT = 1,
COMPONENT = 1 << 2,
TEXT_CHILDREN = 1 << 3,
ARRAY_CHILDREN = 1 << 4,
}
Вот что нужно сделать:
- Определить флаги в shared/shapeFlags.ts
- Определить shape в runtime-core/vnode.tstsДобавить это и вычислить флаг в функциях типа createVNode.
export interface VNode<HostNode = any> { shapeFlag: number }
- Реализовать логику ветвления на основе shape в рендерере.
На этом объяснение этой главы закончено. Давайте начнем реализацию!