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-деревья и непосредственно обновляют их при изменении данных.
К примеру, вот этот компонент:


todos.component.ts
@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>) {}
}

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


todos.component.js
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, информация об обучении или поддержке, вы можете почитать о наших методах работы с клиентами здесь


Комментарии (0)