Google представила пробную версию Scheduler.yield Origin

Google представила пробную версию Scheduler.yield Origin

Создание веб-сайтов, быстро реагирующих на действия пользователя, было одним из самых сложных аспектов веб-производительности, над решением которого команда Chrome усердно работала. Только в этом году было объявлено , что метрика «Взаимодействие с следующей отрисовкой» (INP) перейдет из экспериментального статуса в статус ожидания. Теперь он готов заменить First Input Delay (FID) в качестве Core Web Vital в марте 2024 года.

Продолжая прилагать усилия по созданию новых API-интерфейсов, которые помогут веб-разработчикам сделать свои веб-сайты максимально быстрыми, команда Chrome в настоящее время проводит пробную версию Origin дляscheduler.yield запуска в Chrome версии 115. scheduler.yield— это предлагаемое новое дополнение к API планировщика, которое обеспечивает более простой и лучший способ вернуть управление основному потоку, чем методы, на которые традиционно полагались .

О технологии

В JavaScript для работы с задачами используется модель run-to-completion. Это означает, что при выполнении задачи в главном потоке она выполняется столько времени, сколько необходимо для ее завершения. После завершения задачи управление передается обратно главному потоку, что позволяет ему обрабатывать следующую задачу в очереди.

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

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

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

Google представила пробную версию Scheduler.yield Origin

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

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

Проблема с текущими стратегиями доходности

Распространенный метод получения использует setTimeout значение тайм-аута 0 . Это работает, потому что переданный обратный вызов setTimeout переместит оставшуюся работу в отдельную задачу, которая будет поставлена в очередь для последующего выполнения. Вместо того, чтобы ждать, пока браузер выполнит свои действия самостоятельно, вы говорите: «Давайте разобьем этот большой кусок работы на более мелкие части».

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

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

  • Нажмите верхнюю кнопку с надписью « Периодический запуск задач» , чтобы запланировать время от времени запуск задач блокировки. Когда вы нажмете эту кнопку, в журнале задач появится несколько сообщений с надписью «Выполнено задание блокировки с расширением setInterval.
  • Затем нажмите кнопку с надписью « Выполнить цикл», получая результат setTimeout на каждой итерации .

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

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

Это иллюстрирует распространенную проблему в Интернете: сценарий, особенно сторонний, нередко регистрирует функцию таймера, которая выполняет работу через определенный интервал. Поведение «конец очереди задач», возникающее при передаче, setTimeout означает, что работа из других источников задач может быть поставлена в очередь перед оставшейся работой, которую цикл должен выполнить после передачи.

В зависимости от конкретного приложения это может быть желательным или нежелательным результатом, но во многих случаях именно из-за такого поведения разработчики не хотят так легко отдавать контроль над основным потоком. Уступчивость хороша тем, что пользовательские взаимодействия имеют возможность выполняться раньше, но она также позволяет другим работам, не связанным с пользовательскими взаимодействиями, получить время в основном потоке. Это реальная проблема, но scheduler.yield может помочь ее решить!

Начало работы с scheduler.yield

scheduler.yield доступен под флагом как экспериментальная функция веб-платформы, начиная с Chrome версии 115. У вас может возникнуть один вопрос: «Зачем мне нужна специальная функция для возврата, если setTimeoutона уже есть?»

Стоит отметить, что yield не была целью разработки setTimeout, а скорее приятным побочным эффектом при планировании выполнения обратного вызова в более поздний момент в будущем — даже с нулевым указанным значением тайм-аута. Однако более важно помнить, что при выполнении с помощью setTimeout оставшаяся работа отправляется в конец очереди задач. По умолчанию scheduler.yield оставшаяся работа отправляется в начало очереди. Это означает, что работа, которую вы хотели возобновить сразу после передачи, не отойдет на второй план по сравнению с задачами из других источников (за заметным исключением взаимодействия с пользователем).

scheduler.yield— это функция, которая уступает основному потоку и возвращает Promise при вызове. Это означает, что вы можете await это сделать в async функции:

async function yieldy () { // Do some work... // ... // Yield! await scheduler.yield(); // Do some more work... // ... }

Чтобы увидеть scheduler.yield в действии, сделайте следующее:

  • Перейдите в chrome://flags.
  • Включите эксперимент с функциями экспериментальной веб-платформы . Возможно, после этого вам придется перезапустить Chrome.
  • Перейдите на демонстрационную страницу или используйте ее встроенную версию под этим списком.
  • Нажмите верхнюю кнопку с надписью "Периодически запускать задачи".
  • Наконец, нажмите кнопку с надписью «Выполнить цикл», получая результат scheduler.yield на каждой итерации .

Вывод в поле внизу страницы будет выглядеть примерно так:

Processing loop item 1 Processing loop item 2 Processing loop item 3 Processing loop item 4 Processing loop item 5 Ran blocking task via setInterval Ran blocking task via setInterval Ran blocking task via setInterval Ran blocking task via setInterval Ran blocking task via setInterval

В отличие от демонстрации, в которой используется setTimeout, вы можете видеть, что цикл (даже несмотря на то, что он завершается после каждой итерации) отправляет оставшуюся работу не в конец очереди, а в ее начало. Это дает вам лучшее из обоих миров: вы можете улучшить скорость реагирования на ввод данных на своем веб-сайте, а также гарантировать, что работа, которую вы хотели завершить после передачи, не задерживается.

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

Попробуйте!

Если scheduler.yield вам интересен и вы хотите опробовать его, вы можете сделать это двумя способами, начиная с версии 115 Chrome:

  • Если вы хотите поэкспериментировать scheduler.yield локально, введите chrome://flags в адресную строку Chrome и выберите «Включить» в раскрывающемся списке в разделе «Экспериментальные функции веб-платформы» . Это сделает scheduler.yield (и любые другие экспериментальные функции) доступными только в вашем экземпляре Chrome.
  • Если вы хотите включить scheduler.yield для реальных пользователей Chromium в общедоступном источнике, вам необходимо внедрить пробную версию scheduler.yield Origin . Это позволяет вам безопасно экспериментировать с предлагаемыми функциями в течение определенного периода времени и дает команде Chrome ценную информацию о том, как эти функции используются в полевых условиях. Дополнительную информацию о том, как работают пробные версии, можно найти в этом руководстве .

То, как вы будете использовать scheduler.yield в поддерживаемых браузерах и которые его не поддерживают — зависит от ваших целей. Вы можете использовать официальный полифилл . Полифил полезен, если к вашей ситуации применимо следующее:

  • Вы уже используете scheduler.postTask в своем приложении для планирования задач.
  • Вы хотите иметь возможность ставить задачи и определять приоритеты.
  • Вы хотите иметь возможность отменять или менять приоритет задач с помощью TaskController класса, scheduler.postTask предлагаемого API.

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

// A function for shimming scheduler.yield and setTimeout: function yieldToMain () { // Use scheduler.yield if it exists: if ('scheduler' in window && 'yield' in scheduler) { return scheduler.yield(); } // Fall back to setTimeout: return new Promise(resolve => { setTimeout(resolve, 0); }); } // Example usage: async function doWork () { // Do some work: // ... await yieldToMain(); // Do some other work: // ... }

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

// A function for shimming scheduler.yield with no fallback: function yieldToMain () { // Use scheduler.yield if it exists: if ('scheduler' in window && 'yield' in scheduler) { return scheduler.yield(); } // Fall back to nothing: return; } // Example usage: async function doWork () { // Do some work: // ... await yieldToMain(); // Do some other work: // ... }

scheduler.yield— это интересное дополнение к API-интерфейсу планировщика, которое, как мы надеемся, облегчит разработчикам задачу повышения скорости реагирования по сравнению с текущими стратегиями доходности. Если scheduler.yield API кажется вам полезным, примите участие в нашем исследовании, чтобы помочь его улучшить, и оставьте отзыв о том, как его можно улучшить в дальнейшем.

Начать дискуссию