Поставили await. Интерфейс всё равно висит 😩
Задача простая. Убрать зависание страницы при обработке большого массива данных.
Разработчик нашёл тяжёлый цикл, добавил async, расставил await и отправил на ревью. В описании задачи появилась приятная формулировка: «Оптимизирована обработка данных, устранена блокировка интерфейса».
Код выглядит убедительно:
async function calculate(items) { for (const item of items) { await Promise.resolve() processItem(item) } }
Асинхронная функция, промисы, выполнение приостанавливается на каждой итерации. Осталось проверить.
Нажимаем кнопку. Страница замирает. Индикатор загрузки не появляется. Через пару секунд интерфейс оживает.
Зато теперь асинхронно 👏🏻
В ECMAScript await действительно приостанавливает выполнение асинхронной функции. Её продолжение организуется через задания промисов. Но ECMAScript ничего не обещает про отрисовку кадров.
За браузерный event loop отвечает HTML Standard.
В нём определены task queues, microtask queue и механизм microtask checkpoint.
Обычные задачи выбираются из task queues. А во время контрольной точки браузер выполняет микрозадачи, включая те, которые добавились в процессе выполнения предыдущих.
Наш await Promise.resolve() как раз приводит к постановке продолжения функции в очередь микрозадач.
Одна итерация закончилась, следующая уже ждёт. И так до конца массива.
Пока выполняется эта непрерывная цепочка, браузер не переходит к обновлению отображения.
Получается занятно. Мы тысячи раз приостановили функцию, но так и не дали интерфейсу обновиться.
Индикатор загрузки честно включили. Состояние компонента поменяли. Пользователь индикатора не увидел.
Можно разбить вычисления на порции и планировать их через setTimeout. Между порциями у браузера появится возможность заняться другими задачами и отрисовкой. Хотя гарантии нового кадра после каждого таймера нет.
Можно вынести тяжёлую обработку в Web Worker. Главный поток освободится от вычислений, но появятся вопросы передачи данных и получения результата.
А можно сначала выяснить, зачем мы вообще обрабатываем такой объём данных на главном потоке.
Вариантов хватает. Но ни один не сводится к добавлению слова async.
Особенно прикольно, когда после такой оптимизации кто-нибудь предлагает поставить ещё один await. Для надёжности.
В задаче блокировку устранили. Браузеру об этом пока не сообщили.
· вчера
Химия, химия.. эвент-лупа синяя!! )
0
ответить
коммент скрыт — часть юзеров считает его токсичным или некорректным
коммент удалён