Является ли innerHTML асинхронным?


Я надеюсь, что не буду делать из себя дурака, но я пытаюсь понять, что происходит в этих двух строках кода:

document.body.innerHTML = 'something';
alert('something else');

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

оформить этот codepen чтобы увидеть, что я имею в виду.

обратите внимание, что даже alert in setTimeout(..., 0) не помогает. Похоже, для этого требуется больше циклов событий innerHTML на самом деле обновить страницу.

EDIT:

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

3 96

3 ответа:

настройка innerHTML синхронна, как и большинство изменений, которые вы можете внести в DOM. Однако,визуализация веб-страница-это другая история.

(помните, что DOM означает "модель объекта документа". Это просто "модель", представление данных. Что пользователь видит на своем экране картину, как эта модель должна выглядеть. Таким образом, изменение модели не приводит к мгновенному изменению изображения - требуется некоторое время для обновления.)

запуск JavaScript и рендеринга веб-страницы на самом деле происходит отдельно. Проще говоря, сначала выполняется весь JavaScript на странице (из цикла событий-проверьте это отличное видео для более подробной информации) , а затем после что браузер отображает любые изменения на веб-страницу для пользователя, чтобы увидеть. Вот почему "блокировка" является такой большой проблемой-запуск вычислительно интенсивного кода предотвращает браузер от прохождения шага "run JS" и в шаг "render the page", вызывая страница для замораживания или заикания.

конвейер Chrome выглядит так:

enter image description here

Как вы можете видеть, все JavaScript происходит в первую очередь. Затем страница стилизуется, раскладывается, окрашивается и составляется - "рендер". Не весь этот конвейер будет выполнять каждый кадр. Это зависит от того, какие элементы страницы изменились, если таковые имеются, и как они должны быть повторно переданы.

Примечание: alert() также синхронно и выполняется во время JavaScript шаг, поэтому диалоговое окно предупреждения появляется до того, как вы увидите изменения на веб-странице.

теперь вы можете спросить: "Подождите, что именно запускается на этом шаге JavaScript в конвейере? Весь мой код выполняется 60 раз в секунду?"Ответ " нет", и он возвращается к тому, как работает цикл событий JS. JS-код запускается только в том случае, если он находится в стеке - от таких вещей, как прослушиватели событий, таймауты, что угодно. Смотрите предыдущее видео (очень.)

https://developers.google.com/web/fundamentals/performance/rendering/

Да, это синхронно, потому что это работает (вперед, введите его в консоли):

document.body.innerHTML = 'text';
alert(document.body.innerHTML);// you will see a 'text' alert

причина, по которой вы видите предупреждение перед изменением страницы, заключается в том, что рендеринг браузера занимает больше времени и не так быстро, как ваш javascript, выполняющийся строка за строкой.

The innerHTML свойство actual обновляется синхронно, но визуальная перерисовка, вызванная этим изменением, происходит асинхронно.

визуальный рендеринг DOM является асинхронным в Chrome и не произойдет до тех пор, пока текущий стек функций JavaScript не очистится, и браузер не сможет принять новое событие. Другие браузеры могут использовать отдельные потоки для обработки кода JavaScript и визуализации браузера, или они могут позволить некоторым событиям получить приоритет во время предупреждения остановка выполнения другого события.

вы можете увидеть это двумя способами:

  1. если добавить for(var i=0; i<1000000; i++) { } перед вашим предупреждением вы дали браузеру достаточно времени, чтобы сделать перерисовку, но это не так, потому что стек функций не очистился (add по-прежнему работает).

  2. если вы задержите свой alert через асинхронный setTimeout(function() { alert('random'); }, 1), процесс перерисовки будет идти впереди функции с задержкой setTimeout.

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