Повышение производительности: пошаговое руководство по планированию фоновых задач в JavaScript

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

Понимание блокировки в JavaScript

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

Из-за однопоточной природы любой продолжительный код JavaScript может привести к тому, что браузер перестанет отвечать на запросы. Представьте себе волшебную пикси-обработку, которая выполняет все задачи в браузере. Когда пикси встречает тег <script> или ему нужно запустить функцию JavaScript, он останавливает все остальные задачи и немедленно обрабатывает код. Это блокирующее поведение необходимо для того, чтобы код не мог сделать ничего вредного, например, удалить элементы DOM или перенаправить на другой URL-адрес.

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

Представляем requestIdleCallback

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

Основной синтаксис requestIdleCallback следующий:

requestIdleCallback(callback);

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

Проверка поддержки браузера

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

if ('requestIdleCallback' in window) {
  // requestIdleCallback supported
  requestIdleCallback(backgroundTask);
} else {
  // fallback option
  setTimeout(backgroundTask, 1);
}

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

Планирование задач с помощью requestIdleCallback

При использовании requestIdleCallback у вас есть возможность планировать несколько задач последовательно. Давайте рассмотрим пример, демонстрирующий выполнение нескольких задач по порядку:

// Array of functions to run
var tasks = [task1, task2, task3];

if ('requestIdleCallback' in window) {
  // requestIdleCallback supported
  requestIdleCallback(backgroundTask);
} else {
  // fallback option
  while (tasks.length) {
    setTimeout(tasks.shift(), 1);
  }
}

// requestIdleCallback callback function
function backgroundTask(deadline) {
  // Run the next task if possible
  while (deadline.timeRemaining() > 0 && tasks.length > 0) {
    tasks.shift()();
  }
  // Schedulefurther tasks if necessary
  if (tasks.length > 0) {
    requestIdleCallback(backgroundTask);
  }
}

В этом примере у нас есть массив с именем tasks, содержащий функции, которые мы хотим выполнять в качестве фоновых задач. Мы проверяем поддержку браузером requestIdleCallback и соответственно планируем задачи. Если requestIdleCallback поддерживается, мы вызываем функцию backgroundTask, которая будет выполнять задачи в период простоя. Если requestIdleCallback не поддерживается, мы возвращаемся к использованию setTimeout для планирования задач с минимальной задержкой.

Внутри функции backgroundTask мы используем объект deadline, предоставленный requestIdleCallback. Объект deadline имеет два важных свойства:

  • didTimeout: этому свойству присваивается значение true, если необязательное время ожидания, указанное в вызове requestIdleCallback, истекло.
  • timeRemaining(): Эта функция возвращает количество миллисекунд, оставшихся в текущем периоде простоя. Это позволяет нам выделять определенное количество времени для каждой задачи.

Мы используем цикл while, чтобы запустить как можно больше задач за оставшееся доступное время. Функция deadline.timeRemaining() гарантирует, что каждой задаче дается ограниченное количество времени для выполнения. Если осталось больше задач и еще есть доступное время простоя, мы планируем еще requestIdleCallback для продолжения выполнения задач в последующие периоды простоя.

Рекомендации по использованию requestIdleCallback

Хотя requestIdleCallback предоставляет удобный способ планировать фоновые задачи, следует помнить об определенных соображениях:

  1. Разбивка задач. При использовании requestIdleCallback важно разбивать задачи на более мелкие управляемые части. Это гарантирует, что каждая задача может быть завершена в течение выделенного времени простоя, и предотвращает блокировку критических операций. Задачи с непредсказуемым временем выполнения, такие как манипулирование DOM, лучше подходят для requestAnimationFrame обратных вызовов.
  2. Избегайте разрешения обещаний. Будьте осторожны при разрешении или отклонении обещаний в рамках requestIdleCallback обратных вызовов. Обратные вызовы будут выполняться сразу после завершения обратного вызова бездействия, независимо от того, осталось ли еще время. Если разрешение Promise запускает длительную операцию, это может негативно повлиять на скорость отклика страницы.

Заключение

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

Спасибо, что дочитали до этого момента! Если вы еще не являетесь участником Medium, подумайте о том, чтобы поддержать меня. Таким образом, у вас будет неограниченный доступ ко всему контенту на Medium, а я также получу небольшую комиссию.

Дополнительные материалы на PlainEnglish.io.

Подпишитесь на нашу бесплатную еженедельную рассылку новостей. Подпишитесь на нас в Twitter, LinkedIn, YouTube и Discord .