Pull to refresh

Comments 24

Браузер не инициирует лишнюю перерисовку страницы если обращения к DOM API происходят в коде синхронно. "Точечные изменения", которые делают за вас библиотеки - именно так и работают. Из этого следует, что взаимодействовать с DOM напрямую - это вовсе не плохая идея, а напротив, путь к более эффективным решениям. Подтверждением этому является множество современных библиотек, отказавшихся от концепции Virtual DOM. В общем, неплохая статья, где-то до середины.

Браузер не инициирует лишнюю перерисовку страницы если обращения к DOM API происходят в коде синхронно.

Дьявол кроется в деталях — действительно на экране ничего не изменится. А вот вызвать reflow (который может быть весьма вычислительно тяжелым, в зависимости от DOM) в синхронном коде — не особо сложно даже в современнейших браузерах (которые сами по себе сильно оптимизируют reflow/repaint, когда могут).

не особо сложно

Как? Приведите пример.

Поменять что-то в элементе и тут же спросить у него, например, offsetHeight. Вроде ещё недавно такое приводило к рефлоу, хотя может быть сейчас оптимизировали и это.

Хороший пример. Показывает, что получение результатов вычисления требует этих самых вычислений, независимо от степени оптимизации. Ну, то есть, если специально запрашивать рефлоу и он произойдет - то это ожидаемое поведение. Я же говорю о ЛИШНИХ перерисовках, которые никак не оптимизируются на уровне синхронизации с Virtual DOM, потому как при этой синхронизации используется тот-же самый синхронный вызов методов DOM API.

Тут есть такой момент - меняем мы один элемент, а потом спрашиваем что-то от другого. При этом часто нам нужно именно прошлое значение свойства, а не пересчитанное с учётом изменения другого элемента. Грубо говоря, в идеале рендер должен происходить так: сначала прочитали из дома всё, что нам нужно, потом обновили дом с учётом прочитанного. Но это не масштабируется. Когда мы разбиваем на компоненты, каждый из них начинает читать и писать вперемешку, что приводит к лишним пересчётам и неожиданным результатам. Тут бы иметь какую-то форму версионирования или откладывания фактических изменений до завершения рендера.VDOM с эти конечно худо-бедно справляется, но цена за это непомерная. IDOM в этом свете выглядит гораздо лучше.

Библиотека https://github.com/wilsonpage/fastdom в принципе позволяет такое сделать и при разбиении на компоненты: все вызовы чтения/изменения DOM в компонентах надо делать через fastdom.measure() и fastdom.mutate() , а библиотека сама их сгруппирует.

Я же говорю о ЛИШНИХ перерисовках, которые никак не оптимизируются на уровне синхронизации с Virtual DOM, потому как при этой синхронизации используется тот-же самый синхронный вызов методов DOM API.

Ну так это всё никак не регулируется спецификациями — это на самом деле чисто browser-specific поведение, что, например, тот же хром не будет делать лишних движений, если может обойтись без reflow. А какой-нибудь старый или просто местячковый браузер — вполне может.


Но, разумеется, общего неправильного посыла статьи это не меняет, потому что как ниже правильно заметили, vdom — он про сохранение привычных абстракций, а не про оптимизацию быстродействия. В конце концов, никто за десятилетия не выкатил разгромных бенчмарков, в которых реакт бы рвал всех по производительности. Совсем наоборот, когда ты ангулярщикам рассказываешь про то, что в реакте лишний раз render() страшно дернуть (много возни с vdom и легко получить брутальный performance hit на ровном месте в некоторых не особо экзотичных обстоятельствах), они на тебя смотрят немного с жалостью.

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

Про сохранение абстракций — хорошая формулировка, согласен (если добавить к ней «в том числе и...»). Но общий посыл не о том, что VDOM позволяет оптимизировать быстродействие, и не про сам VDOM как таковой. А про то, как вообще с изменением подходов и задач развивалось взаимодействие с DOM. Как решения, дававшие плюсы при одном подходе, оказывались минусами при другом, и это приводило к следующей итерации. Как и в любой статье — что-то упрощено, да. Это неизбежно, ведь и весь путь изменений в работе с DOM не был «предначертан заранее», это результат многих итераций, чтобы получить искомое. Текущее состояние тоже не финал, что-то да придет на смену.

Сравнение на примере точечного изменения тоже не совсем корректно, да и сейчас, как совершенно верно замечено, подход меняется.

UFO just landed and posted this here

Мда, столько костылей и библиотек, только для того, чтобы обойти суровую особенность DOM

которой нет

UFO just landed and posted this here

Хотите сказать что Virtual DOM чудесным образом уменьшает это все при добавлении одной ноды в дерево?

Я открывал профилировщик и сравнивал React с одной мало известной библиотекой - результат время на рендеринг без изменений, процессор и память в разы больше утилизируются при использовании Virtual DOM

Хотите сказать что Virtual DOM чудесным образом уменьшает это все при добавлении одной ноды в дерево?

Когда говорят что virtual-dom очень быстрый, то обычно сравнивают какое-нибудь точечное изменение в DOM, с заменой какого-нибудь большого узла целиком. Аргументируют это тем. что за счёт vDom и реконсиляции библиотека знает что поменять, а ваше %frameworkname% нет и патчит всё по хардкору.


И откровенно говоря, в те времена когда появился React это было более-менее правдиво. Много SPA тех времён и правда нещадно экплуатировали innerHTML, потому что это было просто. Прогнал новые данные по функции-шаблону, получил кусок HTML, заменил старый на новый. По пути потерял весь state вроде позиции скролла, курсор, :focus и пр…


Сейчас это уже совсем не так, и все популярные решения стараются бить по DOM как можно более точечно. Например, если используется observable, то можно сделать автоматически отдельную подписку на нужные значения, от которых зависит какой-нибудь attribute. Ну и разница выходит в BigO, который очень разный. Где-то идёт зависимость от числа задействованных реактивных элементов, а где-то от числа нод на сравнение с прошлым слепком.

UFO just landed and posted this here
  1. Не будет оно каждый раз перерендериваться. Браузеры не совсем дураки разрабатывают.

  2. Попробуйте в Реакте перенести жирный кусок VDOM из одного родителя в другой - он перерендерит всё с нуля вместо 1 операции с DOM.

Вот интересно. А есть решения где п2 как-то иначе сработает? Имею ввиду автоматику, не вручную. Наверное для этого нужна некая глобальная идентификация таких звеньев. $mol?

Virtual DOM был придуман не для оптимизации перерисовки, а для того чтобы натянуть сову на глобус - заменить innerHTML и продолжать генерить страницы как привыкли.

Эх, жаль не могу голосовать, Ваш ответ вот самый-самый в точку?

А я могу поставить плюс и поставлю?, только немного переформулирую — не только для оптимизации, но и для сохранения привычных абстракций (как сказали выше в комментах). Одно другому не противоречит.

Angular — единственный фреймворк большой тройки, изначально построенный на архитектуре с использованием template, когда все компоненты пишутся с использованием шаблонов

Я бы сказал, что React (с его клонами) - чуть ли не единственный, где не "используются template".

Sign up to leave a comment.

Articles