Чи внутрішній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.