Поверхностный анализ работы DOM на библиотеках JavaScript

Приветствую Вас, дорогие читатели! В данной статье мы рассмотрим работу DOM на таких JavaScript библиотеках, как Vue, React, Angular. Материал поможет понять принцип работы, конечно, самый лучший способ разобраться в той или иной теме — это практика. В этой статье я привел несколько примеров для лучшего понимания материала.

Поверхностный анализ работы DOM на библиотеках JavaScript

Real DOM vs Shadow DOM vs Virtual DOM

Перед сравнением работы DOM на определенной библиотеке. Давайте рассмотрим, какие DOM есть, чем они отличаются, рассмотрим примеры.

1. Real DOM, или проще говоря DOM, обозначает объектную модель документа, и в это время представление в памяти нашего HTML в виде объектов. У нас есть несколько элементов нашего HTML, представленных в виде вложенных узлов, показанных в форме дерева. На картинке можете увидеть наглядный пример:

Поверхностный анализ работы DOM на библиотеках JavaScript

Для управления поведением узла нашего дерева мы используем querySelector. document. querySelector получает элемент из дерева и далее с помощью атрибутов мы можем работать над поведением.

Поверхностный анализ работы DOM на библиотеках JavaScript

2. Shadow DOM – это относительно новая функция DOM, которая позволяет вам создавать собственные компоненты. Например, кнопки воспроизведения и паузы, которые мы видим на странице, отсутствуют в Real DOM.

Поверхностный анализ работы DOM на библиотеках JavaScript

Видео-компонент – это пользовательский компонент, который был создан Chrome с использованием Shadow DOM. Chrome не отображает Shadow DOM по умолчанию, но мы можем включить в настройках. После включения в узле-родителе video мы видим дочерние узлы.

Поверхностный анализ работы DOM на библиотеках JavaScript

Все js-скрипты в данном примере скрыты от пользователя. Chrome делает работы за нас. Еще одно преимущество Shadow DOM заключается в том, что CSS-стили не влияют на дочерние узлы пользовательского компонента, который предоставляет Chrome. Такие пользовательские компоненты мы тоже можем написать.

3. Virtual DOM – абстракция поверх существующего DOM. То есть, у нас при изменении конкретных элементов дерева обновляется не всё дерево, а только измененные нами элементы. Проще говоря, идет сравнение между Real DOM и Virtual DOM. Такой процесс называется согласованием.

Поверхностный анализ работы DOM на библиотеках JavaScript

Сравнение принципа работы на библиотеках JavaScript

React использует паттерн проектирования «Наблюдатель» (observer). При изменении состояния компонента, React обновляет VDOM. После обновления VDOM, React сравнивает его текущую версию с предыдущей. Этот процесс называется «поиском различий» (diffing).

React и Vue примерно одинаково работают, они используют Virtual DOM. Но есть несколько отличий. По сравнению с React — Vue, напротив, использует алгоритм «обновления на месте» (in-place patching), который обновляет виртуальное DOM на месте без полного сравнения со старым состоянием.

React использует систему «подъема состояния» (state lifting) и «контекст» (context) для отслеживания изменений, тогда как Vue предоставляет систему наблюдателей (observers) и реактивных свойств (reactive properties). Vue также предлагает вычисляемые свойства (computed properties) и наблюдаемые свойства (watchers) для более удобной работы с реактивностью.

Пример реализации на Vue.

Родительский компонент:

<template> <div> <child-component :count="count" @increment="incrementCount" /> </div> </template> <script> import ChildComponent from './ChildComponent.vue'; export default { components: { ChildComponent }, data() { return { count: 0 }; }, methods: { incrementCount() { this.count++; } } }; </script>

Дочерний компонент:

<template> <div> <p>Count: {{ count }}</p> <button @click="$emit('increment')">Increment</button> </div> </template> <script> export default { props: ['count'] }; </script>

Пример реализации на React.

Родительский компонент:

import { useState, createContext } from 'react'; import ChildComponent from './ChildComponent'; const MyContext = createContext(); const ParentComponent = () => { const [count, setCount] = useState(0); return ( <div> <MyContext.Provider value={{ count, setCount }}> <ChildComponent /> </MyContext.Provider> </div> ); }; export default ParentComponent;

Дочерний компонент:

import { useContext } from 'react'; import MyContext from './MyContext'; const ChildComponent = () => { const { count, setCount } = useContext(MyContext); return ( <div> <p>Count: {count}</p> <button onClick={() => setCount(count + 1)}>Increment</button> </div> ); }; export default ChildComponent;

Angular, в отличие от Vue и React, использует Incremental DOM. Incremental DOM используется компанией Google для внутренних нужд. Его основная идея такова: «Каждый компонент компилируется в набор инструкций, которые создают DOM-деревья и непосредственно обновляют их при изменении данных».

Например, код компонента, который мы видим ниже:

@Component({ selector: 'todos-cmp', template: ` <div *ngFor="let t of todos|async"> {{t.description}} </div> ` }) class TodosComponent { todos: Observable<Todo[]> = this.store.pipe(select('todos')); constructor(private store: Store<AppState>) {} }

Будет скомпилирован в:

var TodosComponent = /** @class */ (function () { function TodosComponent(store) { this.store = store; this.todos = this.store.pipe(select('todos')); } TodosComponent.ngComponentDef = defineComponent({ type: TodosComponent, selectors: [["todos-cmp"]], factory: function TodosComponent_Factory(t) { return new (t || TodosComponent)(directiveInject(Store)); }, consts: 2, vars: 3, template: function TodosComponent_Template(rf, ctx) { if (rf & 1) { // create dom pipe(1, "async"); template(0, TodosComponent_div_Template_0, 2, 1, null, _c0); } if (rf & 2) { // update dom elementProperty(0, "ngForOf", bind(pipeBind1(1, 1, ctx.todos))); } }, encapsulation: 2 }); return TodosComponent; }());

Данный пример взял из этой статьи.

Инкрементальный DOM в Angular, по сравнению с Vue и React, напротив, использует более прямой подход, обновляя только те части реального DOM, которые фактически изменились, без необходимости сравнивать целые деревья виртуального DOM.

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

Компания Google и поставила перед собой задачу — сделать так, чтобы приложения показывали хорошую производительность на мобильных устройствах. А значит, была необходима оптимизация размера бандла и объёма потребляемой памяти.

Подводя итоги, мы поверхностно рассмотрели, как используется DOM на определенной библиотеке. Для общего понятия принципа работы хорошо подойдет новичкам. Понимание какой-либо технологии, алгоритма приходит со временем. Надеюсь, статья помогла разобраться в этой области.

4 комментария

Это какая то какафония слов..
Ключевое слово в аббревиатуре DOM это Модель. Это правила, по которым формируются html, xml документы. Эти правила формируют интерфейс взаимодействия внешних программ с объектами документа.
Все скриптоперделки - это прибамбас сбоку, который к смыслу DOM не имеет никакого отношения от слова совсем.
Все эти поделия лишь пользуются данной Моделью для манипулирования структурой документа.
Боже мой.

Ответить

Спасибо за комментарий. DOМ, действительно, представляет собой модель документа, которая определяет структуру HTML и XML документов. Скрипты на JavaScript используют DOM для взаимодействия с элементами страницы и изменения их структуры. Я в целях изучения, расписал поверхностно принцип обработки элементов на определенной библиотеке. Надеюсь, это прояснило Ваше недопонимания.

Ответить