Чи внутрішнійHTML асинхронний?


102

Я сподіваюся, що не зроблю себе дурнем, але намагаюся зрозуміти, що відбувається в цих двох рядках коду:

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

Що я зауважую, - це те, що попередження надходить до того, як HTML було оновлено (а може бути, але сторінка не була оновлена ​​/ перефарбована / будь-що інше)

Оформіть цей коден, щоб побачити, що я маю на увазі

Будь ласка , зверніть увагу , що навіть покласти alertв setTimeout(..., 0)не допомагає. Схоже, потрібно більше циклів подій для innerHTMLфактичного оновлення сторінки.

Редагувати:

Я забув згадати, що я користуюся Chrome і не перевіряв інші веб-переглядачі. Схоже, його видно лише в Chrome. Тим не менш мене все ще цікавить, чому це відбувається.


4
Це характерно для Chrome.
trincot

2
@trincot дякую! Я забув згадати, що я користуюся Chrome і не пробував іншого браузера, перш ніж запитувати. Чи є у вас якісь довідки?
apieceofbart

16
Зміна DOM є синхронною. Візуалізація DOM насправді відбувається після очищення стека JavaScript. developers.google.com/web/fundamentals/performance/rendering JavaScript> Стиль> Макет> Фарба> Композит. (Принаймні для Chrome. Схожі інші браузери.)
jered

2
лише здогадка: блокування попередження запобігає перегляду браузера на крок перефарбовування, тому, хоча DOM змінився, його ще не було дозволено перефарбовувати; знову ж таки, лише здогадка.
zzzzBov

2
@qbolec перевірити це відео: youtu.be/r8caVE_a5KQ
apieceofbart

Відповіді:


131

Встановлення InternalHTML є синхронним, як і більшість змін, які ви можете внести в DOM. Однак надання веб-сторінки - це вже інша історія.

(Пам'ятайте, DOM означає "Модель об'єкта документа". Це просто "модель", представлення даних. Те, що бачить користувач на своєму екрані, - це зображення, як повинна виглядати ця модель. Отже, зміна моделі не відбувається миттєво змінити малюнок - оновлення потребує певного часу.)

Запуск JavaScript та візуалізація веб-сторінки фактично відбуваються окремо. Якщо простіше сказати, спочатку весь JavaScript на сторінці запускається (з циклу подій - ознайомтеся з цим чудовим відео для отримання більш детальної інформації), а потім після цього браузер вносить будь-які зміни на веб-сторінку, яку бачить користувач. Ось чому "блокування" - це така велика справа - запуск обчислювально інтенсивного коду не дозволяє браузеру пройти крок "запустити JS" і перейти до кроку "візуалізації сторінки", внаслідок чого сторінка замерзає або заїкається.

Трубопровід Chrome виглядає приблизно так:

введіть тут опис зображення

Як бачите, все JavaScript відбувається спочатку. Тоді сторінка стилюється, викладається, малюється та компонується - "візуалізація". Не весь цей конвеєр буде виконувати кожен кадр. Це залежить від того, які елементи сторінки змінилися, якщо такі є, і як їх потрібно відредагувати.

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

Ви можете запитати "Тримайся, що саме запускається на кроці" JavaScript "на трубопроводі? Чи весь мій код працює 60 разів на секунду?" Відповідь "ні", і вона повертається до того, як працює цикл подій JS. Код JS запускається лише у тому, що він знаходиться в стеці - від таких речей, як слухачі подій, тайм-аути, і все. Дивіться попереднє відео (справді).

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


1
дякую за відповідь. Я знав деякі подробиці про цикл подій і т. Д. Цей конвеєр має ідеальний сенс, але як показують приклади, він не той самий у кожному браузері. Якщо інші веб-переглядачі чекають, коли сторінка буде перефарбована, перш ніж з’явиться попередження, це означає, що між натисканням кнопки та відображенням самого сповіщення може виникнути велика затримка. Я спробую з цим пограти пізніше.
apieceofbart

@apieceofbart Інші веб-переглядачі можуть також просто асинхронно перефарбовувати сторінку, зупиняючи речі JavaScript, поки користувач не вирішить вікно попередження. Це не означає, що вони повинні чекати, коли відбудеться перефарбування.
Йонас Шефер

27

Так, це синхронно, тому що це працює (вперед, введіть його в консолі):

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

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


Дякую, я це перевірив. Але це має бути щось специфічне для Chrome - воно працює, як очікувалося в інших браузерах. А може, це їхній недолік у тому, що вони чекають перефарбовування сторінки, щоб перейти до наступного рядка javascript?
apieceofbart

3
Чи відповідає сповіщення правильний текст? ( textна моєму прикладі) Це відповість на ваше запитання, чи це синхронно. Візуалізація браузера проти виконання Javascript - це яблуко та апельсини :)
d -_- b

Це не має нічого спільного з питанням
apieceofbart

1
Ви запитуєте буквально "Чи внутрішнійHTML асинхронний?". Якщо значення можна використовувати відразу після синхронності, ні? Я думаю, ви маєте намір запитати більше про візуалізацію сторінок, а не про синхронну якість InternalHTML.
d -_- b

8
Так, питання було явно неправильним, але я не знав, що йому задати. Якби я знав правильний, якби, мабуть, знайшов би відповідь. Я не мав на увазі бути зла, дякую за відповідь все одно!
apieceofbart

6

innerHTMLВластивість фактичного ж оновлюється синхронно, але візуальні перемальовування , що ця зміна викликає асинхронно.

Візуальне відображення DOM є асинхронним у Chrome і не відбудеться доти, доки не буде очищено поточний стек функцій JavaScript і браузер не зможе прийняти нову подію. Інші веб-переглядачі можуть використовувати окремі потоки для обробки коду JavaScript і візуалізації браузера, або вони можуть дозволити деяким подіям отримати пріоритет, коли попередження зупиняє виконання іншої події.

Ви можете бачити це двома способами:

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

  2. Якщо ви затримаєте свій alertасинхронний setTimeout(function() { alert('random'); }, 1)процес, процес перемальовування перейде до функції, що затримується setTimeout.

    • Це не працює, якщо ви використовуєте тайм-аут 0, можливо, тому що Chrome надає пріоритет черзі подій 0тайм-аутам перед будь-якими іншими подіями (або принаймні перед перемальовуванням подій).

Дякую за відповідь! Будь ласка, що це навіть setTimeout(func, 1)не працювало кожен раз, перевірте це відео: youtu.be/r8caVE_a5KQ
apieceofbart
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.