Надеюсь, я не буду выставлять себя дураком, но я пытаюсь понять, что происходит в этих двух строках кода:
document.body.innerHTML = 'something';
alert('something else');
Я наблюдаю, что предупреждение отображается до того, как HTML был обновлен (или, может быть, он был, но страница не была обновлена / перекрашена / что-то еще)
Проверить этот код чтобы понять, что я имею в виду.
Пожалуйста , обратите внимание , что даже положить alert
в setTimeout(..., 0)
не помогает. Похоже, требуется больше циклов событий дляinnerHTML
фактического обновления страницы .
РЕДАКТИРОВАТЬ:
Забыл упомянуть, что использую Chrome и не проверял другие браузеры. Похоже, это видно только в Chrome. Тем не менее меня все еще интересует, почему это происходит.
javascript
html
google-chrome
dom
за штуку
источник
источник
Ответы:
Установка innerHTML является синхронной, как и большинство изменений, которые вы можете внести в DOM. Однако рендеринг веб-страницы - это совсем другая история.
(Помните, что DOM означает «объектная модель документа». Это просто «модель», представление данных. Пользователь видит на экране изображение того, как эта модель должна выглядеть. Таким образом, изменение модели не происходит мгновенно. поменять картинку - обновление займет некоторое время.)
На самом деле запуск JavaScript и рендеринг веб-страницы происходят отдельно. Проще говоря, сначала запускается весь JavaScript на странице (из цикла событий - просмотрите это отличное видео для более подробной информации), а затем, после этого, браузер отображает любые изменения на веб-странице, чтобы пользователь мог их увидеть. Вот почему «блокировка» так важна - выполнение кода с интенсивными вычислениями не позволяет браузеру пройти этап «запустить JS» и перейти к этапу «визуализации страницы», что приводит к зависанию страницы или заиканию.
Конвейер Chrome выглядит так:
Как видите, сначала выполняется весь JavaScript. Затем страница оформляется, оформляется, раскрашивается и компонуется - «рендеринг». Не весь этот конвейер будет выполнять каждый кадр. Это зависит от того, какие элементы страницы были изменены, если таковые были, и как их нужно перерисовать.
Примечание:
alert()
также синхронно и выполняется во время шага JavaScript, поэтому диалоговое окно предупреждения появляется до того, как вы увидите изменения на веб-странице.Теперь вы можете спросить: «Погодите, что именно запускается на этом этапе« JavaScript »в конвейере? Весь мой код выполняется 60 раз в секунду?» Ответ - «нет», и он возвращается к тому, как работает цикл событий JS. Код JS запускается, только если он находится в стеке - от таких вещей, как прослушиватели событий, таймауты и т. Д. Смотрите предыдущее видео (действительно).
https://developers.google.com/web/fundamentals/performance/rendering/
источник
Да, это синхронно, потому что это работает (введите в консоли):
Причина, по которой вы видите предупреждение до того, как увидите изменение страницы, заключается в том, что рендеринг в браузере занимает больше времени и не так быстро, как ваш javascript выполняется построчно.
источник
text
в моем примере) Это ответит на ваш вопрос, синхронно ли это. Браузерный рендеринг против выполнения Javascript - яблоко и апельсины :)innerHTML
Свойство фактического же обновляется синхронно, но визуальные перерисовки , что это изменение вызывает асинхронно.Визуальный рендеринг DOM является асинхронным в Chrome и не произойдет до тех пор, пока текущий стек функций JavaScript не будет очищен и браузер не сможет принять новое событие. Другие браузеры могут использовать отдельные потоки для обработки кода JavaScript и рендеринга браузера, или они могут позволить некоторым событиям получить приоритет, в то время как предупреждение останавливает выполнение другого события.
Вы можете увидеть это двумя способами:
Если вы добавите
for(var i=0; i<1000000; i++) { }
перед предупреждением, вы дадите браузеру достаточно времени на перерисовку, но этого не произошло, потому что стек функций не очищен (add
все еще работает).Если вы откладываете
alert
через асинхронныйsetTimeout(function() { alert('random'); }, 1)
режим, процесс перерисовки будет идти впереди функции, отложенной на setTimeout.0
, возможно, потому, что Chrome отдает приоритет очереди событий0
тайм-аутам перед любыми другими событиями (или, по крайней мере, перед событиями перерисовки).источник
setTimeout(func, 1)
не каждый раз получалось