Кадр анимации запроса вызывается постоянно

Пытаюсь понять RequestAnimationFrame и как он работает внутри.

Браузер имеет основной поток, который представляет собой цикл событий. Цикл событий может быть заполнен различными асинхронными событиями, такими как взаимодействие с пользователем, срабатывание таймеров, завершение сетевых вызовов и события, запускающие макет и рисование, например. ввод или JS.

Таким образом, когда функция JS аннулирует макет DOM или вызывает перерисовку, основной поток браузера перерисовывает слои, которые необходимо обновить, а поток компоновщика загружает обновленные текстуры в графический процессор, где происходит окончательный композитинг, и полученное изображение отображается на экране. .

Итак, у меня сложилось впечатление, что браузеры выполняют отрисовку только тогда, когда это действительно необходимо. Если вы фиксируете события на временной шкале Chrome Dev Tools на статической странице, на которой ничего не происходит, абсолютно никакие события не фиксируются (без макета, без рисования, без запуска кадра анимации). Имеет смысл.

Но затем вы запускаете следующий код в консоли:

function onBeforeNextRepaint() {
    requestAnimationFrame(onBeforeNextRepaint);

    console.log('About to paint ...');
}

onBeforeNextRepaint();

Теперь вы снова захватываете события временной шкалы и замечаете события «Анимационный кадр запущен», и ваша консоль регистрируется с сообщением «О рисовании ...».

вызывается onBeforeNextRepaint

Анимационный кадр запущен

Согласно MDN,

Метод Window.requestAnimationFrame() сообщает браузеру, что вы хотите выполнить анимацию, и запрашивает у браузера вызов указанной функции для обновления анимации перед следующей перерисовкой.

Это означает, что браузер постоянно рисует и, следовательно, вызывает мою функцию для регистрации сообщения перед каждой перерисовкой. Я предполагаю, что браузеры поддерживают планировщик, который вызывает вызовы краски с частотой, соответствующей частоте обновления экрана.

Теперь мое замешательство заключается в следующем:

  1. Основной поток браузера постоянно перерисовывает, генерирует текстуры и загружает текстуры в графический процессор, а также выполняет вызовы отрисовки (регулируется в соответствии с частотой обновления экрана)? (Звучит неэффективно)
  2. Это причина, по которой мой обратный вызов onBeforeNextRepaint вызывается постоянно?
  3. Если 1 и 2 верны, то почему при первом захвате временной шкалы я не фиксирую события «Обновить деревья слоев» и «Композитные слои»?

person Prashant    schedule 21.02.2015    source источник


Ответы (2)


Я думаю, вы неправильно понимаете описание, данное MDN. Позвольте мне сломать его.

Метод Window.requestAnimationFrame() сообщает браузеру, что вы хотите выполнить анимацию.

Это означает, что он сообщит браузеру, что вы хотите предварительно сформировать анимацию, которая потребует перерисовки. Но для этого нам понадобится запустить некоторый код.

и запрашивает, чтобы браузер вызывал указанную функцию для обновления анимации перед следующей перерисовкой.

Это означает, что непосредственно перед следующей перерисовкой, которая потребуется для анимации, вызовите мою функцию обратного вызова.

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

person Alexander O'Mara    schedule 21.02.2015
comment
Спасибо, Александр, ваш ответ помог. Я хочу получить и другие мнения, поэтому я подожду, прежде чем приму окончательный ответ :) - person Prashant; 22.02.2015

Следующая запись в блоге действительно помогла мне понять как все работает.

Отсюда:

По сути, вся функция цикла событий может быть проиллюстрирована этим кодом:

while (eventLoop.waitForTask()) {  
    const taskQueue = eventLoop.selectTaskQueue()
    if (taskQueue.hasNextTask()) {
        taskQueue.processNextTask()
    }

    const microtaskQueue = eventLoop.microTaskQueue
    while (microtaskQueue.hasNextMicrotask()) {
        microtaskQueue.processNextMicrotask()
    }

    if (shouldRender()) {
        applyScrollResizeAndCSS()
        runAnimationFrames()
        render()
    }
}

И изобразить так:

Диаграмма, показывающая очередь задач/микрозадач/и кадров анимации

person Izhaki    schedule 22.09.2016
comment
Просто читая этот ответ. Спасибо за ссылку на этот замечательный пост и ваш ответ. - person Prashant; 26.04.2017