Главный поток браузера — дорогой ресурс: как им управлять
The Browser's Main Thread Is Expensive
Разбираемся, почему оптимизация фронтенда не сводится к сети и размеру бандла. Главный поток браузера выполняет и JavaScript, и отрисовку, и обработку событий, поэтому его блокировка замораживает интерфейс. Статья объясняет, как работает главный поток, почему код не обязательно медленный, и предлагает четыре стратегии: разбиение, группировка, приоритизация и откладывание задач. На примерах с чатом и анимациями показано, как уступать поток браузеру, чтобы интерфейс оставался отзывчивым.
Код не медленный. Просто именно ему выпало держать главный поток.
- martinald
Хорошая статья, и я бы хотел, чтобы это было гораздо более известно.
Проблема в том, что она слишком сосредоточена на интерактивности. В действительности, 90%++ медленных сайтов медленные не из-за интерактивности, а потому что они грузят огромные бандлы React/Next.js и имеют очень тяжелую работу по гидратации.
_так много_ сайтов имеют бандлы размером >10 МБ, которые нужно скачать, распарсить и прогидратировать.
Я даже видел (многие) сайты, в которых уложено несколько SPA друг в друга.
Если у вас медленное интернет-соединение и/или слабый процессор, страница практически непригодна в течение многих десятков секунд, и никакое количество уступок после гидратации бандла это по-настоящему не решит.
- nerdralph
Я согласен с большей частью статьи, но хотел бы уточнить следующее:
> Чтобы экран выглядел плавным, кадры должны отрисовываться с частотой обновления дисплея. На наиболее распространенном 60-герцовом дисплее это означает 60 кадров в секунду, или около 16,6 миллисекунд на кадр.
Совершенно не обязательно точно соответствовать частоте обновления дисплея. С монитором 144 Гц, 72 FPS будут выглядеть плавными для подавляющего большинства людей, и даже 48 FPS будут выглядеть плавными для большинства. Я согласен, что более высокая частота кадров лучше, но есть убывающая отдача.
- kccqzy
Вот проблема, о которой я думал в своем последнем frontend-проекте: проекту нужно было разбирать строку, введенную пользователем, для подсветки синтаксиса. Реализация заключалась в том, чтобы разбирать строку сразу после нажатия клавиши, чтобы пользователь всегда видел правильные цвета. Но меня не отпускала мысль, что если я неправильно спроектировал грамматику, некоторые разборы могут занять более чем линейное время и заблокируют главный поток во время разбора. Но мне не очень хотелось сначала отображать черный текст, разбирать его в веб-воркере, а затем перерисовывать с цветом. Эффект, должно быть, казался дезориентирующим.
В любом случае, я остановил проект по несвязанным причинам, и эта мысль продолжала сверлить мне мозг. Когда я снова возьмусь за проект, я обязательно попробую некоторые техники из статьи.
- jonathanlydall
Отличная статья.
Для меня в ней было мало новой информации, так как я сам применял некоторые из этих техник, основываясь на интуитивном понимании того, как работает и блокируется "поток" рендеринга, но для менее опытного разработчика эта статья должна быть невероятно познавательной и дать прочное понимание происходящего.
Я использовал уступки в любительском проекте [0], который сделал около 15 лет назад, особенно когда нужно было выполнять множество операций отрисовки на canvas. Я также экспериментировал с использованием воркеров для рендеринга частей в фоновом потоке, но в то время не было способа эффективно копировать данные между ними и главным потоком; приходилось отправлять данные как PNG в base64, и накладные расходы на кодирование, декодирование и копирование на canvas приводили к гораздо худшей производительности, чем если бы все делалось в главном потоке.
Сайт также выполняет распаковку Gzip загруженных файлов в JavaScript, и библиотека, которую я нашел в то время, делала всю работу синхронно, поэтому могла легко заблокировать поток UI на 10+ секунд. Я модифицировал её, чтобы она могла уступать каждые 200 мс или около того; этот процесс был очень поучительным, особенно потому, что убедил меня никогда не опускать фигурные скобки после оператора if: я потратил очень много времени, пытаясь понять, почему это не работает, пока наконец не осознал, что добавленный мной оператор не был в блоке if. Дело не в том, что я не понимал, как работают операторы if, а в том, что в моем сознании отсутствие […]
- larodi
Отличная статья, респект! Некоторые из этих техник я применял ранее, и они действительно имеют большое значение. Дело в том, что когда изучаешь/преподаешь JS, обычно остается ограниченное время, чтобы обсудить эти темы, а они более важны, чем кажется.
Весь смысл кооперативной многозадачности в том, чтобы время от времени уступать (обратно планировщику), чтобы он мог обработать отрисовку. Кроме того, при 60fps можно вычислять многое раз в N кадров, и глаз этого не замечает, анимация течет.
Становится еще интереснее, когда задействован WebGPU, но CSS-аниматор действительно очень быстр.
Примечание: некоторые мои недавние работы (цифровые флаеры в стиле newskool) -> bsf.hmsu.org // nouveauxhivers.dub4powder.xyz
- gwbas1c
К сведению: это не только браузерная особенность. Все платформы (Windows, Mac, iOS, Android) обычно имеют однопоточный UI.
- piker
Отличная работа, автор. Мы работаем с WASM и рассматриваем возможность использования веб-воркеров для помощи в рендеринге документов вне главного потока в этом контексте. Я был удивлен, узнав, что ArrayBuffer передается только по ссылке! Возможно, это вариант. Спасибо, что собрали это вместе.
- jkhdigital
Эта статья завершается следующим утверждением:
> Так много в разработке — это компромиссы, и вы должны выбирать в зависимости от ситуации, что в конечном счете сводится к опыту и суждению разработчика.
Это отличная статья, но я думаю, что она немного отстает от жизни, рассматривая проблемы планирования как вопрос "опыта и суждения". Проблема распределения работы по ограниченному ресурсу — одна из старейших и наиболее изученных во всей информатике. Имело бы смысл обратиться к учебнику по этому вопросу, прежде чем изобретать велосипед.