Обновить
11

Full-stack web developer.

5
Подписчики
Отправить сообщение
Все объекты (не только визуальные компоненты) переиспользуются, так что это вполне штатный сценарий.

То есть обновляются значения всех свойств во всей иерархии? Или обновляются только измененные? А массивы как, как определяется, какие элементы в массиве изменились? Или если порядок поменялся, как определяется?


Это тот же dirty checking, только вручную. А если все пересоздается заново — то тот же рендеринг v-dom.


Тут природу не обманешь, в любом из подходов есть неэффективные сценарии.


Например?

Например, из массива чисел подготовить данные для графика; по массиву свободных мест отрисовать доступные к продаже места (учитывая правила продажи); не суть важно.


Рассмотрим каждый подход и вариант с пересозданием или же модификацией:


  • С dirty-checking — разницы особо нет, при модификации будет чуть меньше проверок (или же вообще не распознает изменения). Реальный ДОМ обновится как карта ляжет — может оптимально, а может и пересоздать заново большой кусок.


  • С графом зависимостей — при модификации будет оптимальное изменение, при пересоздании — будет полная перестройка графа. Обновление ДОМ — оптимальное при модификации, полное перестроение в противном случае.


  • С виртуальным ДОМ — либо полная перестройка и реконсиляция при пересоздании, либо частичная перестройка при модификации (и то не факт). Обновление же ДОМ всегда близко к оптимальному.

При этом модификация вручную — это императивный (не "реактивный") код, и он по производительности будет сопоставим с dirty checking и v-dom reconciliation. Пересоздание графа зависимостей же — это самая затратная операция из всех, и если ее делать постоянно, то выигрыша в производительности не будет.


Виртуальный ДОМ — это не серебряная пуля, конечно же, это всего лишь разумный компромисс, который дает аккуратное и предсказуемое (а это не менее важно часто, чем быстрое) обновление реального ДОМ дерева.

Перестроение — это вообще не про реакт, согласны? Это, возможно, про редакс или флакс, но речь разве о них?

Речь про подход реакта. И я тут считал задержку между действием пользователя и появлением реакции на экране, а не только лишь время процессора, проведённое в определёной библиотеке.

Вот, например, описание этой проблемы и костыля к редуксу, для её решения: https://github.com/reactjs/reselect#motivation-for-memoized-selectors

Я же и говорю — это костыли для редакса, не для реакта. Редакс бывает и для Ангуляра, и для Вью, и даже для Нокаута.


На каких же данных вдом может быть быстрее? Уже для 3000 элементов, разница заметна:

1) На больших объектах, со множеством свойств — когда у элемента виртуального ДОМ свойств меньше. 2) На больших массивах (да и объектах), из которых рендерится только часть (то же отфильтрованное меню) — сравнение будет идти по реально отображаемым элементам, а не по всем данным.


Опять же, это все фиксится — подготавливаются модели, заранее фильтруются данные, но, в общем случае, плохие сценарии бывают у всех подходов.


Вы очень смело обобщаете. с какими фреимворками вы работали? работали ли с $mol? сможете придумать для него худший релистичный сценарий?

Я не работал с ним, как я понимаю, это фреймворк с построением графа зависимостей. Плохой сценарий для него — это 1) перестроение виджета по новым данным (при перезагрузке с сервера, например), 2) сложные проекции (селекторы) — производные вычисляемые данные, которые не сделать наблюдаемыми (т.к. они вычисляются каждый раз заново), и, следовательно, ДОМ для них просто тупо перестраивается.

Ну то есть


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

Подход реакта.
Заново формируем то же самое дерево (+50мс),
заново фильтруем его с тем же результатом (+150мс),
заново преобразуем в список пунктов меню (+50мс).… После чего реакт делает дифф с real-dom и применяет разницу (+40мс). Итого — четверть секунды на удаление атрибута у одного элемента и добавление его другому.

Итого — 90мс для списка в 10 000 элементов.


Перестроение — это вообще не про реакт, согласны? Это, возможно, про редакс или флакс, но речь разве о них?


Вы ниже писали, что Ангуляр применяет точечные патчи.
Вы думаете, что это быстрее генерации и сравнения v-dom для списка в 10К элементов? Возможно, но я бы не утверждал. Сравнение произвольных данных может быть как быстрее, так и медленнее в-дом, зависит от данных.


В "реактивных" фреймворках типа MobX или Knockout время тратится на построение графа зависимостей. Будет ли это быстрее, чем в-дом? Может да, а может и нет, зависит будут ли меняться данные, как часто и каким образом они будут меняться.


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


Выбирать фреймворк по производительности, если производительность отличается, ну, пусть даже на 50% — нету смысла, если только заранее не известны узкие места, и они действительно критичные и важные (придуманный пример — обновление котировок, или лотов аукциона, тяжелые графики на SVG, и т.п.).


У всех современных фреймворков производительность удовлетворительная. 80% приложений никогда не испытают проблем с производительностью, а половина тех, что испытают — решат их минимальными исправлениями.

Ничто не мешает использовать реакт, как, скажем, jquery-компоненты, или директивы ангуляра, или еще что-то другое. Но только зачем? App state management библиотеки придумали не потому, что в реакте по-другому нельзя, а потому, что это удобно и имеет преимущества. Об этом говорит и существование байндингов того же redux под многие фреймворки.

А какой еще возможен вариант? Почему он более "успешный"? И в чем проблема его реализовать на реакте?

Для меня лично MobX стойко ассоциируется с Knockout и всеми его болячками.


Плюс не нравится описывать структуру данных модели и загрузку ее данными сервера, как было в Нокауте. Хотя, может быть, в МобХ такой проблемы и нет.

Я имел ввиду качество продукта — соответствие требованиям с приемлемым количеством ошибок.

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

Для этого есть правило первое :)


По сути, формальных критериев для этого нет (и я считаю, не нужно их искать, иначе получите не хороших, а соответствующих). Но по работе и по отношению в команде это видно, и этого достаточно.

UTC DateTime позволяет сравнивать даты из разных часовых поясов, и отображать даты в часовом поясе пользователя. Это дает общую относительную систему координат, и часто этого достаточно.


Но иногда возникают задачи, когда требуется узнать дату и время в системе координат пользователя.


Например, иногда важна именно выбранная дата (без времени), и она может отличатся из-за разницы в часовых поясах. Здесь UTC не поможет, из него нельзя восстановить реально выбранное пользователем значение (без дополнительной информации о часовом поясе, скажем, из профиля).

Самый надежный и хороший подход — это хранить DateTimeOffset, и работать с ним как на сервере, так и на клиенте. Использовать свой формат сериализации (возможно, с фоллбэком в часовую зону по умолчанию, для старых клиентов).


Все остальное, включая хранение UTC, это полумера. UTC решает проблему сравнения дат, но не всегда помогает правильно их отображать.


Вообще, работа с датами — тема довольно неочевидная и с множеством подводных камней, особенно если в некоторых случаях нужны только даты без времени. Нужно всегда (как отметили уже выше) понимать, что именно нужно показать: дату события в часовом поясе пользователя, дату, как ее ввел пользователь или еще что-то.

В смысле "не могут быть однонаправленными" и "притворяться, что обратного потока нет"? Могут быть, и никто не отрицает обратный поток.


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


И событие, к примеру, ввода попадает и обрабатывается в состоянии приложения, и лишь опосредованно изменяет само представление. В этом отличие от двустороннего связывания (как в вашем примере), которое одновременно меняет свойство и контрол. Это затрудняет реализацию некоторых сценариев (например, попробуйте нормально реализовать ввод по маске и тп).

Ну, вы вынесли информацию о выделенном элементе на самый верх, в корень глобального состояния, и расшарили его с меню. Это один из очевидных способов "починки" иерархии (вынести на общий уровень родителя), но с кучей недостатков: общие данные будут стремится на самый верхний уровень, нужны специальные механизмы для получения уведомлений об изменениях, потоки данных не однонаправленные.


Для redux можно решить задачу с меню вообще не имея общего состояния, а лишь подписываясь на события изменения выбранного элемента (и предусмотрев "null-событие" сброса выделения).

Архитектура приложения, особенно бэкенд части, обычно строго иерархическая. У нас есть подсистемы, в них модули, в них компоненты, в компонентах используются другие компоненты и т.д. Все хорошо и красиво, исключения редкие, это хорошо работает и хорошо ложится на ООП.


Во фронтэнде это тоже работает, особенно когда речь идет об отображении данных (или, в терминологии стейт-менеждеров, о "потоке данных из состояния в представление"). Это привело к тому, что многие UI фреймворки ориентированы на создание замкнутых сложных компонентов с внутренним состоянием (как правило, смесью данных, состояния приложения и состояния самого компонента + бизнес логика в смеси с логикой UI).


Это перестает работать хорошо, когда начинается взаимодействие с пользователем. UI паттерны для взаимодействия не иерархичны сплошь и рядом. Возьмем текстовый редактор. У нас есть меню (которое находится на верхнем уровне иерархии компонентов), которое изменяет состояние выбранного абзаца в документе (которые находится на самом нижнем уровне). Состояние пункта меню зависит от нижнего уровня. Это нарушает иерархию (в которой нижний уровень должен зависить от верхнего, но не наоборот).


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


App-state management framework (redux, flux, частично MobX) решают эту проблему радикально — они полностью развязывают иерархию компонентов и иерархию состояния приложения. Плюс они дают единую точку входа для любого действия (своего рода универсальный контроллер), и адресация к нужному элементу — это теперь обязанность контроллера.


Это заодно решает и другую, менее острую и реже встречающуюся, проблему — отображение одних и тех же данных в разных видах.


У этой архитектуры достаточно своих проблем, начиная от многословности и слабой связности, заканчивая тем, что привычные паттерны не работают, переиспользование — это боль и мучения (в отличие от "кинь на форму и настрой свойства" подхода с изолированными компонентами).


Главным вопросом при выборе архитектуры UI должен быть "насколько иерархия данных отличается от ирерархии компонентов". Если она не отличается — инкапсулированные классические компоненты будут отлично работать. Если отличается сильно лучше их сразу развязать, чтобы не городить костыли и в итоге не прийти к самодельному flux-у.

Редьюсеры редко переиспользуются потому, что это обычно часть логики приложения (а не компонента). Поведение именно компонента обычно делается внутренним состоянием этого компонента (и его довольно мало, если разобраться).


Но это все-равно отличается от классических компонентов, где смешана логика приложения и логика компонента. Особенно это видно на сложных компонентах типа гридов, которые на реакте и редаксе теряют 80% своей сложности.


Я не смотрел и не использовал именно redux-forms, и, честно говоря, не совсем понимаю, какую выгоду они несут и что именно автоматизируют.

Подходы к декомпозиции redux-based приложений отличаются от "классических", унаследованных от jQuery-based приложений.


Проблемы с декомпозицией обычно начинаются, когда пытаются эмулировать стейтфулл компоненты на базе редакса.


В редаксе точкой декомпозиции являются именно sub-state + actions + middleware. Это делается довольно неудобно, и ни в какое сравнение не идет, конечно, с "классическими" компонентами, особенно с непривычки. В первую очередь это связано с тем, что точка монтирования зашита в коде middleware и mapStateToXXX.


В редаксе отдельно переиспользуется логика и отдельно переиспользуется UI (в виде dumb components). Ну и, соответсвенно, контейнеры пишем каждый раз.


Но сила редакса в том, что он "развязывает" связь один-к-одному между данными и структурой UI. Он легко позволяет отображать одни и те же данные в нескольких видах, без дублирования кода.


UI вообще часто нелогичен с точки зрения иерархии, часто верхние уровни зависят от нижних, например, добавляются пункты меню в зависимости от выделенной строки в гриде. Редакс это позволяет делать относительно легко (послать экшен можно из любого места), на "классических" компонентах это сделать красиво невозможно без введения аналога сообщений.

А разве архитектура с однонаправленными потоками — это не MVC? Ведь именно MVC постулировала зависимости в одном направлении.


На примере Реакта:


Model -> application state,
View -> JSX
Controller -> Reducer + Middleware, разделение на логику перехода по состояниям и логику взаимодействия с "внешним миром".

Ну или самый простой вариант — это не разносить транзакционные сервисы по разным микросервисам.

PoE слэшер чистой воды, однако возможных билдов очень много, и они реально рабочие (в отличие от того же Диабло 3).


Минус — это дико однообразный геймплей, выбранный билд практически невозможно изменить, умение требует очень сильной прокачки для выживания на высоких уровнях.

Информация

В рейтинге
Не участвует
Откуда
Украина
Дата рождения
Зарегистрирован
Активность