Повышение производительности: пошаговое руководство по планированию фоновых задач в 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 предоставляет удобный способ планировать фоновые задачи, следует помнить об определенных соображениях:
- Разбивка задач. При использовании
requestIdleCallbackважно разбивать задачи на более мелкие управляемые части. Это гарантирует, что каждая задача может быть завершена в течение выделенного времени простоя, и предотвращает блокировку критических операций. Задачи с непредсказуемым временем выполнения, такие как манипулирование DOM, лучше подходят дляrequestAnimationFrameобратных вызовов. - Избегайте разрешения обещаний. Будьте осторожны при разрешении или отклонении обещаний в рамках
requestIdleCallbackобратных вызовов. Обратные вызовы будут выполняться сразу после завершения обратного вызова бездействия, независимо от того, осталось ли еще время. Если разрешение Promise запускает длительную операцию, это может негативно повлиять на скорость отклика страницы.
Заключение
Используя requestIdleCallback, вы можете планировать задачи последовательно, используя доступное время простоя, не блокируя основной поток. Важно разбивать задачи на более мелкие фрагменты и избегать длительных операций, которые могут повлиять на взаимодействие с пользователем.
Спасибо, что дочитали до этого момента! Если вы еще не являетесь участником Medium, подумайте о том, чтобы поддержать меня. Таким образом, у вас будет неограниченный доступ ко всему контенту на Medium, а я также получу небольшую комиссию.
Дополнительные материалы на PlainEnglish.io.
Подпишитесь на нашу бесплатную еженедельную рассылку новостей. Подпишитесь на нас в Twitter, LinkedIn, YouTube и Discord .