Последовательность выполнения и рендеринг событий - PullRequest
0 голосов
/ 17 июня 2020

var con = document.getElementById('con');
con.onclick = function () {
  Promise.resolve().then(function Promise1() {
    con.textContent = 0;
    // requestAnimationFrame(() => con.textContent = 0)
  });
};
<div id="con">this is con</div>

Почему этот код не запускает рендеринг после выполнения микрозадач?

setTimeout(function setTimeout1() {
  console.log('setTimeout1')
}, 0)
var channel = new MessageChannel();
channel.port1.onmessage = function onmessage1() {
  console.log('postMessage');
  Promise.resolve().then(function promise1() {
    console.log('promise1');
  })
};
channel.port2.postMessage(0);
setTimeout(function setTimeout2() {
  console.log('setTimeout2')
}, 0);
console.log('sync');

Почему пост-сообщение выполняется до таймера?

1 Ответ

1 голос
/ 17 июня 2020

Почему этот код не запускает рендеринг после выполнения микрозадач?

Да, иначе вы бы не увидели обновляемый текст ...

Может быть, вы не можете определить это с помощью инструментов разработчика?

Это вероятно , потому что события мыши теперь обычно регулируются до уровня screen-refre sh, что означает что, когда задача, отправляющая событие мыши, будет запущена, вы уже будете в рамке рисования, это может быть по другой причине (потому что, насколько мне известно, таким образом регулируются события mousemove , а не щелкните ...).
Итак, ваш обратный вызов Promise будет выполняться синхронно (только на шестом шаге «установить currentTask в значение null» между ними) перед обновить рендеринг шаги начнутся, и все инструменты разработчика увидят обычную рамку для рисования, как и ожидалось.
Итак, возможно , инструменты разработчика не покажу здесь ничего особенного, но даю en широта вашего утверждения, довольно сложно определить конкретную причину, и это всего лишь моя теория.

Вы можете попытаться подтвердить эту теорию, позвонив requestAnimationFrame изнутри такого события и проверьте, выполнялся ли он в том же событии l oop итерация:

onclick = (evt) => {
  console.clear();
  setTimeout( () => console.log( 'timeout' ), 0 );
  requestAnimationFrame( () => console.log( 'rAF' ) );
};
Click anywhere<br>
If "rAF" gets logged before "timeout", the click event got handled in a painting frame.

Для меня это происходит довольно часто в Chrome и только время от времени в Firefox, но в то же время я знаю Chrome rAF не работает ... так что эта теория довольно слабая.


Почему пост-сообщение выполняется до таймера?

Это будет зависеть от User-Agent (браузера) и от того, когда этот код выполняется, чтобы этот оператор оставался верным, а также, конечно, по причине, по которой это происходит.

In Chrome, они устанавливают минимальное значение 1 мс для значения тайм-аута, передаваемого в setTimeout:

  base::TimeDelta interval_milliseconds =
    std::max(base::TimeDelta::FromMilliseconds(1), interval);

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

В Firefox они обрабатывают задачи, запланированные на setTimeout с низким приоритетом, при планировании из загрузки страницы (это означает, что в Firefox задача сообщения будет фактически запускаться после setTimeout одного, если оба запланированы после загрузки страницы:

function test() {
  setTimeout(function setTimeout1() {
    console.log('setTimeout1')
  }, 0)
  var channel = new MessageChannel();
  channel.port1.onmessage = function onmessage1() {
    console.log('postMessage');
    Promise.resolve().then(function promise1() {
      console.log('promise1');
    })
  };
  channel.port2.postMessage(0);
  setTimeout(function setTimeout2() {
    console.log('setTimeout2')
  }, 0);
  console.log('sync');
}
console.log( 'testing @ page load' );
test();
setTimeout(() => {
  console.log( 'testing after page load' );
  test();
}, 1000 );

/* results in Firefox:

testing @ page load
sync
postMessage
promise1
setTimeout1
setTimeout2
testing after page load
sync
setTimeout1
setTimeout2
postMessage
promise1
*/
).
Итак, в этом конкретном случае загрузки страницы они будут рассматривать задачу сообщения как более важную, чем задачу с тайм-аутом, и когда исполнитель задачи должен будет выбрать, какой задача для выполнения следующей (как часть первого шага модели обработки событий L oop ), она выберет сообщение по истечении времени ожидания.

Но это причуды реализации, и ничто в спецификациях не формализует такое поведение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...