Angular — наш основной инструмент для написания приложения TestMace. В одной из прошлых статей мы затронули тему Ivy рендерера. Самое время поподробнее узнать, чем Ivy отличается от предыдущего движка.

В нашей компании Nrwl мы уже какое-то время находимся в предвкушении возможностей, которые откроет нам и нашим клиентам Ivy. Angular Ivy — это новый движок рендеринга Angular, кардинально отличающийся от всех аналогичных технологий популярных фреймворков тем, что он использует Incremental DOM.
Что такое Incremental DOM и чем он отличается от Virtual DOM?
Проведём сравнительный анализ и выясним почему Incremental DOM является верным решением для Angular.
Принцип работы Virtual DOM
React — довольно распространённый фреймворк, в котором впервые использовался Virtual DOM. Основная идея состоит в следующем:
Каждый компонент создаёт новое VDOM-дерево всякий раз, когда он рендерится. React сравнивает новое дерево с предыдущим, после чего вносит набор изменений в DOM браузера, чтобы привести его в соответствие с новым VDOM-деревом.

Virtual DOM имеет два основных преимущества:
- Возможность использования любого языка программирования для реализации функции рендеринга компонента и отсутствие необходимости в компиляции. React-разработчики главным образом пишут на JSX, но вполне подойдёт и обычный JavaScript.
- В результате рендеринга компонента мы получаем значение, что может пригодиться при тестировании, отладке и т.п.
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; }());
Функция template содержит инструкции для рендеринга и обновления DOM. Обратите внимание, что инструкции не интерпретируются движком рендеринга фреймворка. Они и есть движок рендеринга.
Преимущества Incremental DOM
Почему же в Google решили остановить свой выбор на Incremental DOM, а не на Virtual DOM?
Задача, которую они поставили, — сделать так, чтобы приложения показывали хорошую производительность на мобильных устройствах. А значит, была необходима оптимизация размера бандла и объёма потребляемой памяти.
Чтобы решить поставленные выше задачи:
- Движок рендеринга должен быть tree-shakable
- Движок рендеринга не должен потреблять много памяти
Incremental DOM и tree shakability
При использовании incremental DOM фреймворк не интерпретирует компонент; вместо этого компонент ссылается на инструкции. Если какая-либо инструкция осталась нетронутой, то она не будет использоваться в будущем. Поскольку данная информация известна во время компиляции, можно исключить неиспользуемые инструкции из бандла.

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

Incremental DOM и потребление памяти
Virtual DOM создаёт всё дерево с нуля при каждом повторном рендеринге.

Incremental DOM же не требует памяти для повторного рендеринга представления, если оно не вносит изменения в DOM. Память необходимо будет выделить только в том случае, если будут добавлены или удалены DOM-узлы, а объём выделяемой памяти будет пропорционален производимым изменениям в DOM.

Так как большинство вызовов render/template не вносят никаких изменений (или вносимые ими изменения незначительны), существенная экономия памяти обеспечена.
Incremental DOM победил?
Разумеется, всё не так просто. Например, то, что render-функция возвращает значение, предоставляет отличные возможности, скажем, в тестировании. С другой стороны, пошаговое выполнение инструкций с помощью Firefox DevTools упрощает отладку и профилирование производительности. Эргономичность того или иного способа зависит от используемого фреймворка и предпочтений разработчика.
Ivy + Incremental DOM = ?
Angular всегда строился на использовании HTML и шаблонов (пару лет назад я опубликовал пост, в котором обозначил свои мысли в поддержку данного решения и его эффективности в долгосрочной перспективе). Именно поэтому главный козырь Virtual DOM никогда не будет выигрышным для Angular.
С учётом всего этого, tree shakability и низкого потребления памяти, я считаю разумным выбором использование Incremental DOM в качестве основы нового движка рендеринга.
Если вам необходима консультация по Angular, информация об обучении или поддержке, вы можете почитать о наших методах работы с клиентами здесь


