Все мы знаем, что в React 16 реализована новая стратегия планирования (Fiber): асинхронный и прерываемый, упомянутые в новой стратегии планирования, на самом деле являются двумя API, основанными на браузерных requestIdleCallback и requestAnimationFrame. Хотя в React реализован аналогичный механизм requestIdleCallback, он очень похож, и необходимо понимать эти два API.
Что такое requestIdleCallback?
Если вы беспокоитесь о взаимодействии с пользователем и не хотите, чтобы пользователи чувствовали себя застрявшими из-за каких-то неважных задач (таких как статистическая отчетность), вам следует рассмотреть возможность использования requestIdleCallback. Поскольку предварительным условием для выполнения обратного вызова requestIdleCallback является то, что текущий браузер находится в состоянии ожидания.
requestIdleCallback will schedule work when there is free time at the end of a frame, or when the user is inactive.
Пример использования requestIdleCallback
requestIdelCallback(myNonEssentialWork);
function myNonEssentialWork (deadline) {
// deadline.timeRemaining()可以获取到当前帧剩余时间
while (deadline.timeRemaining() > 0 && tasks.length > 0) {
doWorkIfNeeded();
}
if (tasks.length > 0){
requestIdleCallback(myNonEssentialWork);
}
}
В чем разница между requestIdleCallback и requestAnimationFrame?
Обратный вызов requestAnimationFrame будет выполняться каждый кадр, что является задачей с высоким приоритетом, в то время как обратный вызов requestIdleCallback не обязательно, это задача с низким приоритетом. Веб-страницы, которые мы видим, рисуются браузером кадр за кадром.Принято считать, что когда FPS равен 60, это относительно плавно, а когда FPS выражается однозначным числом, это относится к воспринимаемому пользователем отставанию. браузер делает во фрейме, следующим образом:
Кадр на рисунке включает взаимодействие с пользователем, выполнение js и вызовы requestAnimationFrame, расчеты макета и перерисовку страницы. Если в определенном кадре не так много задач, которые нужно выполнить, и указанные выше задачи выполняются менее чем за 16 мс (1000/60), то у этого кадра будет определенное время простоя, и это время можно будет использовать вполне нормально. выполнить обратный вызов requestIdleCallback, как показано на следующем рисунке:
Когда программный стек пуст и страница не нуждается в обновлении, браузер фактически находится в состоянии простоя, в это время время, оставшееся для выполнения requestIdleCallback, может быть соответствующим образом увеличено до 50 мс, чтобы предотвратить непредсказуемые задачи. (ввод пользователя) от поступления. Отсутствие своевременного ответа может привести к задержкам, воспринимаемым пользователем.
Поскольку requestIdleCallback использует время простоя фрейма, возможно, что браузер всегда находится в состоянии занятости, в результате чего обратный вызов не может быть выполнен. На самом деле это не тот результат, которого мы ожидаем (например, потеря отчетов). то в этом случае нам нужно. Вы передали второй параметр конфигурации timeout при вызове requestIdleCallback?
requestIdleCallback(myNonEssentialWork, { timeout: 2000 });
function myNonEssentialWork (deadline) {
// 当回调函数是由于超时才得以执行的话,deadline.didTimeout为true
while ((deadline.timeRemaining() > 0 || deadline.didTimeout) &&
tasks.length > 0) {
doWorkIfNeeded();
}
if (tasks.length > 0) {
requestIdleCallback(myNonEssentialWork);
}
}
Если он выполняется из-за обратного вызова тайм-аута, на самом деле пользователь может чувствовать себя застрявшим, потому что время выполнения одного кадра должно превышать 16 мс.
Можно ли выполнять операции модификации DOM в requestIdleCallback?
Настоятельно не рекомендуется.Как видно из композиции кадра выше, выполнение обратного вызова requestIdleCallback указывает на то, что предыдущая работа (включая изменения стиля и расчеты макета) была завершена. Если мы изменим DOM в обратном вызове, предыдущие расчеты макета будут недействительными, и если есть операция для получения макета (например, getBoundingClientRect, clientWidth) в следующем кадре, браузер должен выполнить принудительную работу по перекомпоновке, которая сильно повлияет на производительность.Кроме того, поскольку время модификации операции dom непредсказуемо, легко превысить порог времени простоя текущего кадра, так что это не рекомендуется. Рекомендуемый подход заключается в изменении dom в requestAnimationFrame.Вы можете создать фрагмент документа в requestIdleCallback, а затем применить фрагмент в requestAnimationFrame следующего кадра.
Кроме того, что не рекомендуются операции по модификации DOM, в него не рекомендуется помещать операцию разрешения (отклонения) Promise, потому что обратный вызов Promise будет выполняться сразу после выполнения обратного вызова idle, что продлит трудоемкую текущего кадра, поэтому не рекомендуется.
Рекомендуется, чтобы задачи, помещаемые в requestIdleCallback, были небольшими (микрозадачи) и имели предсказуемое время. Рекомендуем прочитать о microTaskздесь
Совместимость requestIdleCallback
рекомендуется пакет npmrequest-idle-callback
использованная литература
Developers.Google.com/Web/updates… medium.com/@Paul_Irish… nuggets.capable/post/684490… инсайты.мысль работает.талант/реагировать-волокно…