Борис Каплуновский (англ.
БСКаплу )
Я работал над отчетом довольно долго и старался сделать его максимально противоречивым.
И начну сразу с противоречия — я в корне не согласен с тем, что веб-компоненты можно использовать.
Вопрос о 300 КБ уже поднимался; Я глубоко убежден, что 300 Кб для Javascript-страницы — это недопустимо большая сумма.
Сегодня я расскажу о довольно глубоком путешествии во фронтенд. Это путешествие началось, когда я обнаружил, что интерфейс aviasales.ru Оно замедляется, и нужно что-то делать.
Это путешествие началось примерно полтора или два года назад, и то, о чем я буду говорить, представляет собой сжатое повествование о том, что я узнал.
Самое критичное, на мой взгляд, в производительности фронтенд-приложений — это рендеринг.
Мы все знаем, что следует избегать работы с DOM. Чем больше вызовов вы сделаете к DOM API, тем медленнее будет работать ваше приложение.
О чем именно мы будем говорить? О правилах игры.
На какие вещи при рендеринге, в работе веб-приложения нужно обратить внимание, какие параметры являются ключевыми для библиотеки шаблонов рендеринга, какие типы шаблонизаторов существуют. Далее я немного пройдусь по костям гигантов, это AngularJS и ReactJS, попробую рассказать, почему они мне не нравятся и почему они тормозят. Расскажу о том, что хорошего я нашел в других шаблонизаторах и о работе, которую мы создали, основываясь на всех вышеперечисленных знаниях.
Наверное, часть зрителей задается вопросом, что означает дайвер внизу экрана? Наша команда разработчиков базируется в Таиланде, и я лично занимаюсь дайвингом.
В моей голове родилась следующая аналогия: если ты находишься под водой, то чем меньше движений ты делаешь, тем больше кислорода ты экономишь, тем больше ты можешь плавать.
С DOM мы видим примерно то же самое — чем меньше обращений к DOM вы сделаете, тем больше вероятность, что пользователь не столкнется с какими-либо проблемами.
Начнем с правил игры.
Пользовательский опыт зависит от скорости инициализации страницы.
Мы все глубоко увлечены кэшированием страниц, но я должен противоречиво сказать, что кэширование не работает. Это не работает, потому что первый контакт человека с сайтом является самым критическим.
Если сайт тормозит при первой загрузке, пользователь может не вернуться к вам во второй раз.
Первоначальная загрузка страницы чрезвычайно важна.
Вторая важная вещь — скорость реакции интерфейса.
Если человек нажимает на кнопку или флажок, а интерфейс не реагирует моментально, пользователь может закрыть сайт и перейти на другой сайт, где интерфейс отзывчив.
Следующее — потребление ресурсов.
На веб-страницах важны два основных показателя: потребление процессора (если вы делаете много ненужных действий, вы нагреваете процессор, и ему не хватает времени просчитывать анимацию на интерфейсе или просто что-то рисовать), кроме того, если вы создаете много ненужных объектов, это создает нагрузку на сборщик мусора.
Если вы нагрузите сборщик мусора, то он будет периодически вызываться, и отзывчивость вашего приложения снизится.
И последний, но не менее важный момент. Размер библиотеки.
Если у вас одностраничное приложение, то вы можете позволить себе 200-300, а иногда и 400 КБ javascript. Однако компонентная сеть в том направлении, в котором мы благополучно движемся, подразумевает, что страницы создаются из разных веб-компонентов.
Более того, эти веб-компоненты часто производятся разными компаниями и поставляются в отдельной упаковке.
Представим себе страницу, на которой вставлено десяток виджетов: виджет курсов валют, погоды, авиабилетов, черт в ступе.
И каждый из этих компонентов весит 300 КБ, и это всего лишь JS. Таким образом, мы легко можем получить страницу весом 5-10 МБ.
Все бы ничего, и Интернет становится все быстрее и быстрее, но появились мобильные устройства, появились медленные сети, и если вы пользуетесь Интернетом не в Москве, а где-нибудь в Екатеринбурге, то сайт размером 15 МБ будет совершенно неприемлем.
роскошь для тебя.
Вот почему размер библиотеки, на мой взгляд, имеет решающее значение.
Ниже я сравниваю несколько библиотек, причем не сравниваю полимеры, не сравниваю по той причине, что 200 Кб для библиотеки веб-компонентов — это слишком много.
Итак, перейдем к теме разговора — шаблонизаторам.
Все мы, кто занимается веб-разработкой, уже привыкли к строковым шаблонизаторам.
Строковые шаблонизаторы — это шаблонизаторы, которые в результате своей работы возвращают нам строку.
Строка, которую мы позже вставим через внутренний HTML в HTML. Это чудесный, древний, всем известный механизм.
Однако он имеет ряд недостатков.
Основным недостатком является то, что каждый раз, когда вы шаблонируете и вставляете во внутренний HTML, вам приходится выбрасывать весь DOM, который был там раньше, и вставлять новый DOM. Насколько я помню, работа с DOM идет очень и очень медленно.
Если вы выкинули 20 тегов с 30 атрибутами и вставили такие же 20 тегов с 10 атрибутами, то это займет значительное количество времени.
20 миллисекунд легко.
Кроме того, механизмы шаблонов строк не позволяют оставлять привязки для быстрого обновления отдельных атрибутов, отдельных текстовых узлов и т. д. Обнаружив эти неоптимальности, мы начали искать, как можно избавиться от этих недостатков, что с этим можно сделать? И первое, что предложил Goggle, было «Использовать DOM API».
Это дело не очень простое.
Но у этого есть свои преимущества.
Это скриншот с сайта jsperf. Тест, показывающий производительность встроенных механизмов шаблонов, которые вставляют фрагменты HTML из InnerHTML и DOM JS. Здесь мы видим производительность на Android на высоте, и видим, что JSDOM API позволяет ускорить рендеринг в несколько раз.
Здесь это примерно в три раза.
При этом в десктопных браузерах такого адского прироста производительности нет. Около шести месяцев назад Google начал обещать всем веб-разработчикам «мобилогеддон».
Это значит, что все сайты, не адаптированные под мобильные устройства, отзывчивые, адаптивные, будут пессимистичны в результатах поиска.
Это означает, что если вы не готовы к мобильным устройствам, трафик Google на ваши сайты просто значительно уменьшится.
По сути, этот слайд наглядно показывает, что с помощью DOM API можно значительно ускорить рендеринг на мобильных устройствах.
И это касается не только Андроидов.
Как вы знаете, все современные устройства Android и iOS используют один и тот же движок WebKit с примерно одинаковым набором оптимизаций, а это значит, что вы получите одинаковый прирост производительности на всех устройствах iOS, если будете рендерить страницы через DOM API.
Однако DOM API довольно громоздкий.
Здесь я перечислил пять основных вызовов, которые можно использовать для создания регионов DOM. Я привел их примерно в том виде, в котором они будут отображаться в коде вашей программы, если вы будете создавать DOM-разделы напрямую через API. Создание одного элемента, на который раньше у вас уходило 15-17, а может и 30-50 символов, через DOM API легко выльется в 5-10 строк кода.
Время программистов ценно, а это значит, что мы не можем заменить HTML ручным программированием DOM.
Вот здесь нам и нужны шаблонизаторы.
Как вы помните, строковые шаблонизаторы медленные, и хотелось бы иметь DOM шаблонизаторы, шаблонизаторы, которые работают через DOM API, но позволяют использовать все вкусности, к которым мы привыкли при работе с обычными шаблонизаторами.
Итак, что же нам дают шаблонизаторы DOM, кроме возможности не использовать нативный JSDOM API? Они позволяют сохранять объекты DOM в переменных для быстрого обновления в дальнейшем.
Используя механизмы шаблонов DOM, вы можете использовать один и тот же раздел DOM несколько раз.
Что я имею в виду? Допустим, мы посещаем страницу интернет-магазина.
Пользователи вводят одну категорию товаров, а в подготовленные шаблоны вставляются данные об одном списке товаров.
Когда человек переходит на другую категорию товаров, в те же шаблоны подставляются другие данные.
По сути, мы не воссоздаем DOM, мы используем те же части DOM для отображения данных.
Это позволяет существенно сэкономить ресурсы процессора, памяти, а иногда и время программистов.
Осознав идею о том, что мне нужен инструмент шаблонизатора DOM, мы пошли смотреть, что уже существует в отрасли, что мы уже можем использовать для быстрой и эффективной работы с DOM и быстрого его рендеринга? Дальше я вам расскажу, где, по моему мнению, оступились гиганты.
Первый гигант, о котором я хочу поговорить, — это AngularJS.
AngularJS, как мне кажется, споткнулся в самом начале.
Если вы использовали его, вы, вероятно, заметили, что все шаблоны передаются клиенту либо в виде разделов DOM (что не очень хороший стиль), либо в виде строк.
После загрузки библиотеки Angular вынужден скомпилировать ваши строки или DOM в реальные шаблоны.
Это происходит на клиенте.
Представим себе интересную ситуацию.
Пользователь заходит на страницу, загружает весь JS, которого для Angular-приложений может быть довольно много — 100-200-300 Кб запросто.
После этого каждый шаблон с разбором строк начинает компилироваться.
Это приводит лишь к одному — первоначальная загрузка Angular-приложений может из-за этой компиляции (во время которой пользователи делают что угодно, кроме работы с сайтом) длиться полсекунды, секунду.
Я встречал сайты, где процесс компиляции шаблона занимал даже две секунды.
Причем эта проблема нарастает как снежный ком: чем больше шаблонов в вашем приложении, чем сложнее ваше одностраничное приложение, тем больше времени мы тратим на первоначальную компиляцию шаблонов.
Следующая проблема в Angular. Все мы помним, что Angular нам продали господа из Google как первый крутейший фреймворк с двусторонней привязкой.
Причем эта двусторонняя привязка реализуется через т.н.
$watchers, которые вы подвешиваете к структурам данных для последующего отображения их в DOM. На слайде интересная картинка, но вы на нее не смотрите.
Единственное, что здесь интересно, это этот замечательный цикл, в течение которого все $watches пересматриваются по всем данным, которые у вас есть в системе.
И, конечно же, в документации и во всех туториалах вам никто не скажет, что $watchers нужно мониторить.
Это приводит буквально к следующему.
В какой-то момент ваше замечательное приложение начинает хорошо тормозить каждые 100 мс.
Анимации начинают тормозить, память начинает подтекать.
Оказывается, разрешить много $watchers просто невозможно.
Как только вы разрешаете много $watchers, ваше приложение начинает самопроизвольно тормозить.
Тут начинаешь умничать, делать что угодно, уменьшать количество $watchers, отказываться от двусторонней привязки в приложении, ради которой ты взял Angular, лишь бы избавиться от тормозов.
Кроме того, мне кажется, что архитектурный недостаток Angular заключается в том, что в Angular не существует ни одного должным образом описанного способа работы с DOM. Директивы на самом деле независимы, каждая из них работает с DOM так, как считает нужным.
И получается, что просматривая директивы Angular, мы можем пометить некоторые директивы как быстрые, некоторые как медленные, а некоторые как очень медленные.
Если вы использовали ng-repeat, то наверняка видели, что если в него запихнуть 100 элементов, и там еще будут $watchers, то рендерить все это будет очень долго.
Проблема настолько обширна, что при работе с Angular (наша предыдущая версия поисковика была построена именно на Angular) нам пришлось написать свой ng-repeat. Наш сотрудник Антон Плешивцев делал это и говорил об этом на многих конференциях.
Кроме того, 50 КБ свёрнутого размера библиотеки, на мой взгляд, всё равно слишком много.
Те.
За что вы платите? Если посмотреть код Angular, то в этих 50 КБ находится проприетарная система классов, очень некачественная, на мой взгляд, версия Underscore. И все это вы получаете совершенно бесплатно в пределах 50 КБ кода.
Следующий.
На мой взгляд, гораздо лучший фреймворк — ReactJS. Судя по тому, как гудит интернет, каждый первый программист, даже не всегда фронтенд-разработчик, использовал Angular и в восторге от него.
Я не думаю, что virtualDOM может ускорить манипуляции с DOM. Посмотрите, что нам предлагает virtualDOM. VirtualDOM — это источник, из которого ReactJS создает настоящий DOM, т.е.
помимо реального DOM, от создания которого никуда не деться (virtualDOM как раз и позволяет его создавать), ReactJS еще хранит в памяти виртуальный DOM, это называется избыточностью.
VirtualDOM немного меньше настоящего DOM, может быть, в 5 раз меньше.
Однако на самом деле вы вынуждены хранить в памяти две копии virtualDOM. Те.
вы сохраняете настоящий DOM, вы сохраняете отражение реального DOM в виртуальном DOM, плюс каждый раз, когда вы создаете элемент div в виртуальном DOM, вы создаете еще одну копию DOM. У тебя был один ДОМ, теперь у тебя три — молодец! Причем при каждом изменении данных вы создаете еще одну копию virtualDOM, это уже третья копия, однако вы создаете ее с нуля.
Это создает серьезную нагрузку на сборщик мусора и процессор.
К тому же, на мой взгляд, библиотека еще толстая - 35 КБ.
И снова ребята решили нарисовать свою систему классов, нарисовать свой лоудэш, оригинальный им почему-то не понравился, и они запихнули это все в 35 КБ.
Кроме того, он содержит виртуальный DOM с мифическим алгоритмом, который якобы дает огромную производительность.
Следующая проблема с virtualDOM и React в частности заключается в том, что ReactJS ничего не знает о семантике ваших данных.
Давайте посмотрим на этот очень простой пример.
Здесь мы видим два вложенных ы, а внутри них еще один ярлык.
Чтобы изменить значение через virtualDOM, алгоритм virtualDOM внутри React вынужден сравнивать три тега и одно текстовое значение.
Если мы знаем семантику данных, нам достаточно сравнить только текстовое значение, просто потому, что в шаблоне написано, что внутри одного всегда есть другой , внутри следующего есть тег.
Зачем нам их каждый раз сравнивать? Это действительно накладные расходы.
Кроме того, если вы программировали на React, то вы знакомы с чистым рендер-миксином.
Суть его в том, чтобы избавиться от работы с виртуальным Домом.
Происходит очень интересная ситуация, близкая к комичной.
Сначала господа из Google пару лет продавали нам React как вещь, которая с помощью virtualDOM чертовски ускоряет работу с DOM, а потом оказывается, что для того, чтобы быстро работать с DOM, вам нужно устранить виртуальныйDOM. Молодец, молодец.
А теперь о другом.
Захотелось посмотреть — может быть, на планете есть библиотеки, есть люди, которые сделали что-то лучше.
Я не пытался найти одну библиотеку, серебряную пулю, но я хотел искать в библиотеках вещи, которые я мог бы использовать либо для ускорения React, либо для создания своей собственной библиотеки.
И вот что я нашел.
Я рассмотрю две интересные библиотеки.
Первый из них — RiotJS. На мой взгляд, RiotJS — это правильный AngularJS, просто потому, что размер библиотеки — 5 КБ.
Ребята взяли точно те же идеи, что были в AngularJS, но не стали переписывать lowdash, а просто сказали: «Зачем? Это уже написано.
" Ребята не переписывали, не придумывали свою систему классов, ничего не делали.
Мы получили библиотеку 5 КБ.
Производительность лучше, чем у AngularJS, идеи точно такие же.
Тем более шаблоны используемые в RiotJS используют семантику данных, что дает хороший прирост производительности.
Но есть еще проблема — компиляция шаблона все равно происходит на клиенте.
Это не очень быстро, но гораздо лучше.
Следующая библиотека, которая привлекла мое внимание, — PaperclipJS.
PaperclipJS использует ряд очень интересных оптимизаций.
В частности, cloneNode используется для создания шаблонов, и позже я покажу, что он дает большой прирост производительности, но такое решение позволяет сделать PaperclipJS более прозрачным, более понятным для разработчика.
Но у этой библиотеки было и два недостатка: она довольно большая — 40 КБ, что больше, чем у React; и, несмотря на хорошие идеи, развитие идет довольно вяло.
Этой библиотеке уже пару лет, однако она еще не вышла из стадии бета-тестирования.
Пообщавшись с этими и другими библиотеками, а также почитав гуру html5, мне удалось составить следующий список приемов, позволяющих ускорить работу с DOM.
Во-первых, это VirtualDOM. Я долго искал его преимущества, и нашел только одно — оно позволяет уменьшить количество обращений к DOM, тем самым увеличивая производительность.
Однако накладные расходы на создание копии DOM, на мой взгляд, все равно значительны.
Сложный алгоритм сравнения, до сих пор окутанный тайной, который используется в React, не так быстр, как нам обещают. Вам понадобится два дня, чтобы понять, как это работает. И всего этого волшебства, о котором говорили в блогах, там, на мой взгляд, нет. Кроме того, virtualDOM страдает от проблемы, заключающейся в том, что алгоритм ничего не знает о структуре данных.
Пока мы ничего не знаем о структуре данных, все наши обертки, все наши элементы макета оказывают негативное влияние на производительность, поскольку в их сравнении должен участвовать алгоритм virtualDOM.
Методы, которые известны очень давно, — это использование cloneNode, о котором я уже говорил в PaperclipJS и DocumentFragment. Эти два метода используются для повышения производительности.
Ни та, ни другая техника, насколько мне известно, не используется ни в AngularJS, ни в ReactJS. Однако на скриншоте бенчмарка с jsperf хорошо видно, что это позволяет ускорить работу с DOM как минимум в три раза.
Довольно хорошая практика, очень рекомендую ее использовать.
Следующий прием, лежащий абсолютно на поверхности, к тому же неявно встречающийся даже в туториале по React, — это предварительное создание DOM-разделов.
Что я имею в виду? Допустим, человек заходит на страницу интернет-магазина электронных чайников.
Введите название чайника, название фирмы чайника, который хотите приобрести.
В этот момент на сервер отправляется поисковый запрос.
Если ваши серверные программисты быстры и молниеносны, то вы можете получить ответ за 20 мс, за эти 20 мс пользователь практически ничего не делает. И в этот момент мы можем создать структуру DOM для данных, которые будут возвращаться с нашего сервера.
Довольно простая практика.
Я не знаю, почему это не получило широкого распространения.
Пользуюсь, получается очень круто.
Итак, что происходит? Отправляем запрос на сервер, пока ждем ответа от сервера, готовим DOM-структуры для данных, которые должны прийти к нам с сервера.
Когда к нам приходит ответ от сервера, нам фактически все равно нужно его проанализировать.
Чаще всего это не просто принятие Json, но и как-то его адаптация.
Если к этому моменту DOM уже готов, то те 2-3-4 мс, которые у нас есть для работы JS, мы можем потратить на адаптацию и вставку данных в DOM и добавление данных на страницу.
Я настоятельно рекомендую использовать это, и эта штука явно не поддерживается во фреймворках, но вы можете создать элемент вручную при отправке запроса на сервер.
Итак, вооружившись всеми этими знаниями, и найдя немного свободного времени по ночам и выходным, я решил написать небольшой прототип, с которым мы и начали работать дальше.
Это храм шаблонизатора.
Он очень простой, очень маленький, буквально менее 2000 строк кода.
Какими свойствами он обладает? Шаблоны компилируются в момент сборки в код JavaScript, т.е.
на клиенте не производится никакой работы, кроме загрузки кода JavaScript. Возможность создания DOM-чанков заранее поддерживается непосредственно в библиотеке.
Библиотека позволяет легко и просто повторно использовать шаблоны.
Размер библиотеки, на мой взгляд, в свёрнутом и gzip-виде более чем скромный — всего 700 байт. Более того, что мне больше всего нравится в нем, так это максимально быстрое обновление DOM.
Далее попробуем разобраться по кусочкам, как это все делается и как работает.
Структура шаблона предельно проста и примитивна.
Это усы, внутри которых подставляются переменные.
Все довольно очевидно, никакой магии.
Кроме того, он поддерживает два дизайна.
Это полная итерация по ключу для циклов и ветвления.
Выражения не поддерживаются.
Некоторое время назад, до появления React, в отрасли преобладало мнение, что никогда не следует вмешиваться в View и Model. Я по-прежнему считаю, что это правильный подход, поэтому если вы хотите использовать сложные выражения, лучше вынести это в отдельный компонент. Если вы помните, есть такие шаблонные Presenter или ViewModel, если вам нужно сложно подготовить данные для отображения в шаблонах, лучше делать это там, а не перетаскивать выражения в шаблоны.
Далее я покажу вам, как с этим работать.
Я считаю, что нет необходимости создавать фреймворк для каждого чиха, что будущее веба, и особенно компонентного веба, за очень маленькими и независимыми библиотеками, не требующими смены религии и вырезания всего предыдущего из программа для его интеграции в них.
Как выглядит работа с шаблоном?
Берем из шаблона именованный шаблон и обновляем в нем данные, вызывая update. И вставьте его в DOM. По сути, это очень похоже на работу с обычным DOM API. После того, как мы использовали шаблон, мы можем удалить его из DOM, вызвав метод удаления.
Все очень просто.
Как создается DOM заранее? Предположим, мы отправили запрос на сервер и знаем, что должны получить с сервера набор чайников.
На этом этапе мы говорим пулу шаблонов: «Создайте кэш на 10 чайников».
Он создается, и в следующий раз, когда мы сделаем тот же вызов get, реальной работы с DOM не будет, мы получим уже подготовленный и отрендеренный шаблон.
Те.
Мы получим шаблон для мгновенной вставки в DOM. Когда лучше всего это использовать? Смотрите, мы отправляем запрос на сервер и у нас есть 20 мс, на самом деле, конечно, не 20, скорее всего это 200-300 мс, за это время мы сможем кэшировать миллионы DOM-узлов, т.е.
достаточно времени.
Второй вариант — кэшировать шаблоны, когда мы ожидаем DOMContentLoaded. Есть проблема с DOMContentLoaded, что очень много обработчиков подписываются на это событие и в результате в момент прихода этого события просыпается чертова туча скриптов, все из которых начинают обрабатывать обратный вызов, и после этого события приложение спит около 100 мс.
Он глубоко верит, что в этом что-то есть.
Чтобы сократить это ожидание, вы можете кэшировать шаблоны DOM заранее, до того, как это событие придет к нам.
Быстро вносите изменения в DOM. Здесь я представляю простой и понятный вызов, он очень похож на то, как происходит обновление в React. Все помнят вызов setState в React, разница лишь в глубине стека.
Если вы видели, насколько глубоко, сколько вызовов функций делает React перед выполнением целевого действия (а наше целевое действие — это, скорее, просто подстановка этого значения в DOM), то вы знаете, что для React это может быть глубина стека 50-60, а может и больше.
Каждый вызов, особенно в динамических языках вроде JavaScript, не дается нам бесплатно.
Это не так медленно, как вызов DOM, но все же не бесплатно.
Temple позволяет сделать эту замену с глубиной стека = 2, т.е.
по сути вызывается update и из него вызывается функция, которая заменяет это значение.
По сути, это функция ценности.
И при глубине стека = 2 мы получаем целевое действие.
В то же время рекомендуется использовать вызов обновления, когда мы хотим изменить сразу несколько значений.
Если мы захотим изменить что-то одно, то это можно сделать еще быстрее прямыми вызовами свойства и тогда эта замена будет произведена с глубиной стека = 1, что физически невозможно быстрее.
Повторное использование шаблонов.
После того, как пользователь сделал поисковый запрос на чайники, насмотрелся на чайники и сделал новый поисковый запрос, мы можем вернуть шаблоны в пул для дальнейшего использования, чтобы их можно было использовать в дальнейшем повторно.
Это также поддерживается платформой, например функциейpool.release.
Далее я попытаюсь продать вам этот инструмент, используя тесты.
Первый эталон.
Ниже я всегда даю ссылку на тест и помню, что в jsperf «больше» означает «лучше».
В данном случае красный — это Temple, а синий — React. Я сравниваю с React, потому что React, наверное, самое быстрое решение, обычно оно в 5 раз быстрее Angular. Итак, что мы здесь видим? Первоначальная инициализация в Temple выполняется на 30 процентов быстрее в Chrom и на 10–15 процентов быстрее в Firefox. Как это произошло? Внутри, в конечном счете, используются один и тот же элемент create, create text и узел addchild. Однако у Темпла глубина стека почти никогда не превышает два.
По сути, мы экономим время исключительно на звонках внутри библиотеки.
Те 35 КБ JavaScript, которые вы загружаете для использования React, дают вам разницу в производительности — длинные стеки.
Следующий тест, который мы придумали и запустили, — это мягкое обновление.
Soft Update — это когда мы подставляем в шаблон те же данные, которые там уже были подставлены.
Это то место, где виртуальныйДОМ должен проснуться и сказать: «Ребята, данные уже есть, ничего делать не нужно».
Скажу сразу, для чистоты экспериментов над virtualDOM я не использовал pure-render-mixin. И оказалось, что оптимизации в самом браузере позволяют сделать это в четыре раза быстрее.
VirtualDOM тормозит в четыре раза.
Идем дальше, жесткое обновление.
Жесткий вверх Теги: #CSS #JavaScript #HTML #Оптимизация клиента #frontendconf #Борис Каплуновский #dom #движок шаблонов
-
Почему Только Антивирус Касперского?
19 Oct, 24 -
Asp.net Core Сегодня: Плюсы И Минусы
19 Oct, 24 -
Просто Будь Хорошим Тв
19 Oct, 24 -
Яндекс.музыка Vs Вконтакте
19 Oct, 24 -
Админы: Команда Или Нет?
19 Oct, 24