Missed the action at this year's Chrome Dev Summit? Catch up with our playlist on YouTube. Watch now.

Оптимизация обработчиков ввода

Обработчики ввода потенциально являются источниками проблем с производительностью в приложениях, поскольку они могут заблокировать завершение кадров, а также вызывать дополнительную (и совершенно ненужную) работу по пересчету макета

TL;DR

  • "Не используйте обработчики ввода с длительным рабочим циклом_– они могут заблокировать прокрутку."
  • Не изменяйте стили в обработчиках ввода.
  • Оптимизируйте обработчики; запоминайте значения событий и реализуйте изменения стилей при следующем обратном вызове функции requestAnimationFrame.

Не используйте обработчики ввода с длительным рабочим циклом

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

Облегченная прокрутка; только компоновщик.

Однако, если прикрепить обработчик ввода, например touchstart, touchmove или touchend, поток компоновщика должен будет подождать завершения выполнения рабочего цикла этого обработчика, поскольку может быть вызвана функция preventDefault() и прокрутка будет остановлена. Даже если функция preventDefault() не вызывается, компоновщик должен ждать, а выполняемая пользователем прокрутка будет заблокирована, что может привести к подвисанию или пропуску кадров.

Тяжелая прокрутка; компоновщик заблокирован на JavaScript.

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

Не изменяйте стили в обработчиках ввода

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

Если внутри одного из таких обработчиков вносится визуальное изменение, то в начале выполнения обратного вызова requestAnimationFrame необходимо будет применить изменение стиля. Если после этого выполнить чтение визуальных свойств в начале обратного вызова requestAnimationFrame, как рекомендуется в статье "Не используйте большие, сложные макеты и избегайте подтормаживания макетов", вы вызовите принудительный синхронный перерасчет макета!

Тяжелая прокрутка; компоновщик заблокирован на JavaScript.

Оптимизируйте обработчики прокрутки

Обе описанные выше неполадки имеют одно решение: следует всегда откладывать внесение визуальных изменений до следующего обратного вызова requestAnimationFrame:

function onScroll (evt) {

  // Store the scroll value for laterz.
  lastScrollY = window.scrollY;

  // Prevent multiple rAF callbacks.
  if (scheduledAnimationFrame)
    return;

  scheduledAnimationFrame = true;
  requestAnimationFrame(readAndUpdatePage);
}

window.addEventListener('scroll', onScroll);

Кроме того, обработчики ввода при этом останутся необременительными, а это отлично, поскольку теперь прокрутка или касания при выполнении кода с большим объемом вычислений не будут блокироваться!