Является ли innerHTML асинхронным?
Надеюсь, я не буду дурить сам, но я пытаюсь понять, что происходит в этих двух строках кода:
document.body.innerHTML = 'something';
alert('something else');
Я наблюдаю, что предупреждение отображается до того, как HTML был обновлен (или, может быть, он есть, но страница не была обновлена /перекрашена/независимо)
Ознакомьтесь с этим codepen, чтобы понять, что я имею в виду.
Обратите внимание, что даже размещение alert
в setTimeout(..., 0)
не помогает. Похоже, для обновления страницы требуется больше циклов событий для innerHTML
.
EDIT:
Я забыл упомянуть, что я использую Chrome и не проверяю другие браузеры. Похоже, это видно только в Chrome. Тем не менее меня все еще интересует, почему это происходит.
Ответы
Ответ 1
Настройка innerHTML является синхронной, как и большинство изменений, которые вы можете внести в DOM. Тем не менее, создание веб-страницы - это совсем другая история.
(Помните, что DOM означает "Document Object Model".Это просто "модель", представление данных. То, что пользователь видит на своем экране, - это представление о том, как должна выглядеть эта модель. мгновенно изменить изображение - требуется некоторое время для обновления.)
Запуск JavaScript и отображение веб-страницы происходит фактически отдельно. Проще говоря, сначала выполняется весь JavaScript на странице (из цикла событий - проверьте это отличное видео для более подробной информации), а затем после этого браузер отображает любые изменения на веб-странице для просмотра пользователем. Вот почему "блокировка" - это большое дело - работающий с интенсивным вычислением код не позволяет браузеру пройти шаг "запустить JS" и шаг "сделать страницу", заставляя страницу замораживать или заикаться.
Конвейер Chrome выглядит следующим образом:
![введите описание изображения здесь]()
Как вы можете видеть, сначала выполняется JavaScript. Затем страница оформляется, выкладывается, нарисована и составлена - "рендер". Не весь этот конвейер будет выполнять каждый кадр. Это зависит от того, какие элементы страницы были изменены, если они есть, и как их нужно переизлучить.
Примечание: alert()
также синхронно и выполняется во время действия JavaScript, поэтому перед тем, как вы увидите изменения на веб-странице, появится диалоговое окно предупреждения.
Теперь вы можете спросить: "Держись, что именно запускается на этом этапе" JavaScript "в конвейере? Все ли мой код работает 60 раз в секунду?" Ответ "нет", и он возвращается к тому, как работает цикл событий JS. JS-код запускается только в том случае, если он находится в стеке - от таких вещей, как прослушиватели событий, тайм-ауты, что угодно. Смотрите предыдущее видео (действительно).
https://developers.google.com/web/fundamentals/performance/rendering/
Ответ 2
Да, это синхронно, потому что это работает (идите, введите его в консоль):
document.body.innerHTML = 'text';
alert(document.body.innerHTML);// you will see a 'text' alert
Причина, по которой вы видите предупреждение перед тем, как вы видите изменение страницы, заключается в том, что рендеринг браузера занимает больше времени и не так быстро, как ваш javascript, выполняющийся строкой.
Ответ 3
Фактическое свойство innerHTML
обновляется синхронно, но визуальное перерисовка, вызванное этим изменением, происходит асинхронно.
Визуальный рендеринг DOM асинхронен в Chrome и не произойдет до тех пор, пока не удалит текущий стек функций JavaScript, и браузер не сможет принять новое событие. Другие браузеры могут использовать отдельные потоки для обработки кода JavaScript и браузера, или они могут позволить некоторым событиям получать приоритет, а предупреждение останавливает выполнение другого события.
Это можно увидеть двумя способами:
-
Если вы добавите for(var i=0; i<1000000; i++) { }
перед своим предупреждением, вы предоставили браузеру много времени для перерисовки, но это не так, потому что стек функций не очищен (add
все еще работает).
-
Если вы задержите alert
с помощью асинхронного setTimeout(function() { alert('random'); }, 1)
, процесс перерисовки будет превзойти функцию, задержанную setTimeout.
- Это не работает, если вы используете тайм-аут
0
, возможно, потому, что Chrome предоставляет приоритет очереди событий 0
тайм-аутам перед любыми другими событиями (или, по крайней мере, перед событиями перерисовывания).