Почему оповещение появляется перед фоновыми изменениями?

#javascript

#javascript #HTML

Вопрос:

Итак, в последнее время я пробовал разные вещи и получил этот фрагмент кода в своем скрипте:

 document.body.bgColor = "red";
alert("hello");
 

Но в Chrome сначала появляется диалоговое окно предупреждения, и только после того, как я его закрою, меняется фон моего тела. В Firefox я получаю ожидаемое поведение с изменением фона тела на красный, за которым следует всплывающее окно.

Я знаю, что мы не должны полагаться на оповещения и аналогичные элементы управления браузером, но может ли кто-нибудь сказать мне, происходит ли это потому, что поведение не соответствует стандартам, или это потому, что мое понимание синхронного выполнения приведенного выше кода неверно?

Ответ №1:

Процесс рендеринга имеет собственный жизненный цикл и не блокирует поток javascript. Они оба работают независимо.

Решение состоит в том, чтобы «приостановить» выполнение JavaScript, чтобы позволить потокам рендеринга наверстать упущенное. Это можно сделать с помощью простого setTimeout набора 0

 document.body.style.backgroundColor = "red";

setTimeout(function() {
  alert("hey");
}, 0)
 

Обратите внимание, что bgColor это устарело с 2003 года со спецификацией DOM Level 2. Текущий способ установки цвета фона элемента — via element.style.backgroundColor .

Комментарии:

1. Спасибо. Это помогло. Одна вещь, которая меня беспокоит, если это гарантирует, что рендеринг завершится до alert() setTimeout() выполнения inside? Я имею в виду, для более сложного CSS, есть ли событие, подобное onStylesApplied или что-то, что может подключиться к процессу рендеринга?

2. Вы можете вызвать столько операций стиля, сколько захотите, перед setTimeout вызовом.

3. Этот ответ неверен. Рендеринг не зависит от выполнения javascript. Оба выполняются одним и тем же потоком и оба блокируют друг друга. Предупреждение приостанавливает выполнение javascript, и рендеринг не может выполняться до тех пор, пока javascript не будет выполнен полностью. setTimeout() помещает оповещение в очередь обратного вызова, которая вызывает оповещение после рендеринга.

4. Избегайте использования a setTimeout() of Zero ( 0 ) . Хотя сначала это сработало для меня, я заметил, что если я переместил мышь (сразу после нажатия кнопки, которая инициировала оповещение), изменения, которые я внес в DOM перед вызовом alert() , все равно не будут работать. Я тестировал с 10 , но в итоге пошел 100 , так как он работал все время (для того, что мы делали).

Ответ №2:

Простейший обходной путь будет выглядеть так:

 document.body.bgColor = "red";
setTimeout(function() {
        window.alert('Hello There!');
    },  10);
 

Значение тайм-аута «9» является минимальным в моем случае, если я использую <9, предупреждение появляется первым.

Ответ №3:

Скорее всего, вы можете принудительно изменить цвет фона перед появлением диалогового окна, уступив на короткое время перед открытием предупреждения, что позволит браузеру перерисовать.

 setTimeout(function () { alert("hello"); }, 1);