Повышение производительности: пошаговое руководство по планированию фоновых задач в 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 .