Découvrez comment identifier les interactions lentes dans les données de votre site Web afin de trouver des possibilités d'amélioration de son temps d'interaction avant la prochaine peinture.
Les données sur le terrain vous indiquent comment les utilisateurs réels interagissent avec votre site Web. Il met en évidence les problèmes que vous ne pouvez pas trouver uniquement dans les données de laboratoire. En ce qui concerne l'Interaction to Next Paint (INP), les données sur le terrain sont essentielles pour identifier les interactions lentes et fournir des indices essentiels pour les résoudre.
Dans ce guide, vous allez découvrir comment évaluer rapidement l'INP de votre site Web à l'aide des données sur le terrain du rapport d'expérience utilisateur Chrome pour déterminer s'il présente des problèmes d'INP. Vous apprendrez ensuite à utiliser la version d'attribution de la bibliothèque JavaScript Web Vitals et les nouveaux insights qu'elle fournit à partir de l'API Long Animation Frames (LoAF) pour collecter et interpréter les données sur le terrain pour les interactions lentes sur votre site Web.
Commencez par CrUX pour évaluer l'INP de votre site Web
Si vous ne collectez pas de données d'utilisation réelles auprès des utilisateurs de votre site Web, CrUX peut être un bon point de départ. CrUX collecte des données de champ auprès d'utilisateurs Chrome réels qui ont accepté d'envoyer des données de télémétrie.
Les données d'expérience utilisateur Chrome (CrUX) apparaissent dans différents domaines, selon la portée des informations que vous recherchez. CrUX peut fournir des données sur INP et d'autres Core Web Vitals pour:
- des pages individuelles et des origines entières à l'aide de PageSpeed Insights ;
- Types de pages. Par exemple, de nombreux sites Web d'e-commerce proposent des types "Page d'informations détaillées sur le produit" et "Page d'informations détaillées sur le produit". Vous pouvez obtenir des données CrUX pour des types de pages uniques dans la Search Console.
Pour commencer, vous pouvez saisir l'URL de votre site Web dans PageSpeed Insights. Une fois que vous avez saisi l'URL, les données de champ correspondantes (si elles sont disponibles) s'affichent pour plusieurs métriques, y compris l'INP. Vous pouvez également utiliser les boutons d'activation/de désactivation pour vérifier vos valeurs INP pour les dimensions mobiles et ordinateurs.
Ces données sont utiles car elles vous indiquent si vous avez un problème. Cependant, l'expérience utilisateur Chrome ne peut pas vous indiquer ce qui est à l'origine du problème. Il existe de nombreuses solutions de surveillance des utilisateurs réels (RUM, Real User Monitoring) qui vous permettent de recueillir vos propres données de terrain auprès des utilisateurs de votre site Web pour vous aider à répondre à cette question. L'une des options consiste à rassembler ces données de champ vous-même à l'aide de la bibliothèque JavaScript web-vitals.
Collecter des données sur le terrain avec la bibliothèque JavaScript web-vitals
La bibliothèque JavaScript web-vitals
est un script que vous pouvez charger sur votre site Web pour collecter des données sur le terrain auprès des utilisateurs de votre site. Vous pouvez l'utiliser pour enregistrer un certain nombre de métriques, y compris l'INP dans les navigateurs compatibles.
La version standard de la bibliothèque web-vitals peut être utilisée pour obtenir des données INP de base auprès des utilisateurs sur le terrain :
import {onINP} from 'web-vitals';
onINP(({name, value, rating}) => {
console.log(name); // 'INP'
console.log(value); // 512
console.log(rating); // 'poor'
});
Pour analyser les données de terrain de vos utilisateurs, vous devez les envoyer quelque part :
import {onINP} from 'web-vitals';
onINP(({name, value, rating}) => {
// Prepare JSON to be sent for collection. Note that
// you can add anything else you'd want to collect here:
const body = JSON.stringify({name, value, rating});
// Use `sendBeacon` to send data to an analytics endpoint.
// For Google Analytics, see https://github.com/GoogleChrome/web-vitals#send-the-results-to-google-analytics.
navigator.sendBeacon('/analytics', body);
});
Toutefois, ces données ne vous disent pas beaucoup plus que CrUX. C'est là qu'intervient la génération d'attributions de la bibliothèque web-vitals.
Aller plus loin avec la création d'attribution de la bibliothèque web-vitals
La compilation d'attribution de la bibliothèque Web Vitals fournit des données supplémentaires que vous pouvez obtenir auprès des utilisateurs sur le terrain pour vous aider à mieux résoudre les interactions problématiques qui affectent l'INP de votre site Web. Ces données sont accessibles via l'objet attribution
affiché dans la méthode onINP()
de la bibliothèque :
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, rating, attribution}) => {
console.log(name); // 'INP'
console.log(value); // 56
console.log(rating); // 'good'
console.log(attribution); // Attribution data object
});
En plus de l'INP de la page elle-même, la version d'attribution fournit de nombreuses données qui vous aideront à comprendre les raisons des interactions lentes, y compris la partie de l'interaction sur laquelle vous devez vous concentrer. Il peut vous aider à répondre à des questions importantes, par exemple :
- "L'utilisateur a-t-il interagi avec la page pendant son chargement ?"
- "Les gestionnaires d'événements de l'interaction ont-ils été exécutés pendant une longue période ?"
- "Le code du gestionnaire d'événements d'interaction a-t-il été retardé ? Si oui, qu'est-ce qui se passait d'autre sur le thread principal à ce moment-là ?"
- "L'interaction a-t-elle généré beaucoup de travail de rendu qui a retardé l'affichage du frame suivant ?"
Le tableau suivant présente certaines des données d'attribution de base que vous pouvez obtenir à partir de la bibliothèque. Elles peuvent vous aider à identifier certaines causes générales des interactions lentes sur votre site Web :
Clé d'objet attribution
|
Données |
---|---|
interactionTarget
|
Un sélecteur CSS pointant vers l'élément qui a généré la valeur INP de la page (par exemple, button#save ).
|
interactionType
|
Type d'interaction, par exemple clics, pressions ou saisies au clavier. |
inputDelay *
|
Délai de réponse à l'entrée de l'interaction. |
processingDuration *
|
Temps écoulé entre le début de l'exécution du premier écouteur d'événement en réponse à l'interaction de l'utilisateur et la fin du traitement de l'écouteur d'événement. |
presentationDelay *
|
Délai de présentation de l'interaction, qui se produit à partir de la fin des gestionnaires d'événements jusqu'au moment où le frame suivant est peint. |
longAnimationFrameEntries *
|
Entrées du LoAF associé à l'interaction. Pour en savoir plus, consultez la page suivante. |
À partir de la version 4 de la bibliothèque Web Vitals, vous pouvez obtenir des insights encore plus détaillés sur les interactions problématiques grâce aux données qu'elle fournit avec les répartitions de la phase INP (délai d'entrée, durée de traitement et délai de présentation) et l'API Long Animation Frames (LoAF).
API Long Animation Frames (LoAF)
Le débogage des interactions à l'aide de données de terrain est une tâche ardue. Toutefois, grâce aux données du MdF, il est désormais possible d'obtenir des informations plus précises sur les causes des interactions lentes, car le LoAF expose un certain nombre de codes temporels détaillés et d'autres données que vous pouvez utiliser pour identifier les causes précises, et surtout, où se trouve la source du problème dans le code de votre site Web.
La version d'attribution de la bibliothèque Web Vitals expose un tableau d'entrées LoAF sous la clé longAnimationFrameEntries
de l'objet attribution
. Le tableau suivant liste quelques éléments clés de données que vous pouvez trouver dans chaque entrée de la liste d'autorisations d'accès :
Clé d'objet d'entrée LoAF | Données |
---|---|
duration
|
Durée du frame d'animation long, jusqu'à la fin de la mise en page, mais en excluant la peinture et le compositing. |
blockingDuration
|
Durée totale pendant laquelle le navigateur n'a pas pu répondre rapidement en raison de tâches longues. Ce temps de blocage peut inclure des tâches longues exécutées en JavaScript, ainsi que toute tâche de rendu longue ultérieure dans le frame. |
firstUIEventTimestamp
|
Code temporel de l'événement mis en file d'attente pendant le frame. Utile pour déterminer le début du délai d'entrée d'une interaction. |
startTime
|
Le code temporel de début de la trame. |
renderStart
|
Date de début du rendu du frame. Cela inclut tous les rappels requestAnimationFrame (et les rappels ResizeObserver , le cas échéant), mais éventuellement avant le début des tâches de style/mise en page.
|
styleAndLayoutStart
|
En cas de modification du style ou de la mise en page dans le cadre. Peut être utile pour déterminer la durée du travail de style/mise en page en tenant compte des autres codes temporels disponibles. |
scripts
|
Tableau d'éléments contenant des informations d'attribution de script contribuant à l'INP de la page. |
Toutes ces informations peuvent vous en dire beaucoup sur ce qui ralentit une interaction. Toutefois, le tableau scripts
que les entrées LoAF affichent devrait vous intéresser particulièrement :
Clé d'objet d'attribution de script | Données |
---|---|
invoker
|
Le demandeur. Cela peut varier en fonction du type d'appelant décrit dans la ligne suivante. Des valeurs telles que 'IMG#id.onload' , 'Window.requestAnimationFrame' ou 'Response.json.then' peuvent être des exemples d'appelants. |
invokerType
|
Type de l'appelant. Il peut s'agir de 'user-callback' , 'event-listener' , 'resolve-promise' , 'reject-promise' , 'classic-script' ou 'module-script' .
|
sourceURL
|
URL du script d'où provient l'image longue de l'animation. |
sourceCharPosition
|
Position du caractère dans le script identifié par sourceURL .
|
sourceFunctionName
|
Nom de la fonction dans le script identifié. |
Chaque entrée de ce tableau contient les données présentées dans ce tableau, qui vous fournissent des informations sur le script à l'origine de l'interaction lente et sur la raison pour laquelle il en est responsable.
Mesurer et identifier les causes courantes des interactions lentes
Pour vous donner une idée de la façon dont vous pouvez utiliser ces informations, ce guide explique comment utiliser les données LoAF présentées dans la bibliothèque web-vitals
pour déterminer certaines causes des interactions lentes.
Durée de traitement longue
La durée de traitement d'une interaction correspond au temps nécessaire pour que les rappels du gestionnaire d'événements enregistrés pour l'interaction s'exécutent jusqu'à la fin, ainsi que tout autre événement pouvant se produire entre eux. La bibliothèque Web Vitals affiche les durées de traitement élevées :
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {processingDuration} = attribution; // 512.5
});
Il est naturel de penser que la principale cause d'une interaction lente est que le code du gestionnaire d'événements a pris trop de temps à s'exécuter, mais ce n'est pas toujours le cas. Une fois que vous avez confirmé que c'est bien le problème, vous pouvez aller plus loin avec les données LoAF :
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {processingDuration} = attribution; // 512.5
// Get the longest script from LoAF covering `processingDuration`:
const loaf = attribution.longAnimationFrameEntries.at(-1);
const script = loaf?.scripts.sort((a, b) => b.duration - a.duration)[0];
if (script) {
// Get attribution for the long-running event handler:
const {invokerType} = script; // 'event-listener'
const {invoker} = script; // 'BUTTON#update.onclick'
const {sourceURL} = script; // 'https://example.com/app.js'
const {sourceCharPosition} = script; // 83
const {sourceFunctionName} = script; // 'update'
}
});
Comme vous pouvez le voir dans l'extrait de code précédent, vous pouvez utiliser les données LoAF pour identifier la cause exacte d'une interaction avec des valeurs de durée de traitement élevées, y compris :
- L'élément et son écouteur d'événements enregistré.
- Fichier de script (et position des caractères dans celui-ci) contenant le code du gestionnaire d'événements de longue durée.
- Nom de la fonction.
Ce type de données est inestimable. Vous n'avez plus besoin de chercher à savoir exactement quelle interaction (ou quel gestionnaire d'événements) était responsable des valeurs de durée de traitement élevées. De plus, comme les scripts tiers peuvent souvent enregistrer leurs propres gestionnaires d'événements, vous pouvez déterminer si c'est votre code qui en est à l'origine ou non. Pour le code que vous contrôlez, vous devez optimiser les tâches longues.
Retards d'entrée longs
Bien que les gestionnaires d'événements de longue durée soient courants, d'autres éléments de l'interaction doivent être pris en compte. Une partie se produit avant la durée de traitement, ce qui est appelé le délai d'entrée. Il s'agit du temps écoulé entre le moment où l'utilisateur lance l'interaction et celui où les rappels du gestionnaire d'événements commencent à s'exécuter. Cela se produit lorsque le thread principal traite déjà une autre tâche. La version d'attribution de la bibliothèque Web Vitals peut vous indiquer la durée du délai d'entrée pour une interaction :
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {inputDelay} = attribution; // 125.59439536
});
Si vous remarquez que certaines interactions présentent des délais d'entrée élevés, vous devez déterminer ce qui se passait sur la page au moment de l'interaction qui a causé le long délai d'entrée. Cela se résume souvent à savoir si l'interaction s'est produite pendant le chargement de la page ou après.
Est-ce que le problème est survenu lors du chargement de la page ?
Le thread principal est souvent le plus chargé lorsque la page est en cours de chargement. Pendant ce temps, toutes sortes de tâches sont mises en file d'attente et traitées, et si l'utilisateur essaie d'interagir avec la page pendant que toutes ces tâches sont en cours, cela peut retarder l'interaction. Les pages qui chargent beaucoup de code JavaScript peuvent démarrer la compilation et l'évaluation des scripts, ainsi que l'exécution de fonctions pour préparer une page aux interactions des utilisateurs. Cette tâche peut gêner l'utilisateur s'il interagit au moment de cette activité. Vous pouvez savoir si c'est le cas pour les utilisateurs de votre site Web :
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {inputDelay} = attribution; // 125.59439536
// Get the longest script from the first LoAF entry:
const loaf = attribution.longAnimationFrameEntries[0];
const script = loaf?.scripts.sort((a, b) => b.duration - a.duration)[0];
if (script) {
// Invoker types can describe if script eval blocked the main thread:
const {invokerType} = script; // 'classic-script' | 'module-script'
const {sourceLocation} = script; // 'https://example.com/app.js'
}
});
Si vous enregistrez ces données sur le terrain et que vous constatez des retards d'entrée élevés et des types d'appelants de 'classic-script'
ou 'module-script'
, il est juste de dire que l'évaluation des scripts sur votre site prend beaucoup de temps et qu'ils bloquent le thread principal suffisamment longtemps pour retarder les interactions. Vous pouvez réduire ce temps de blocage en divisant vos scripts en petits bundles, en différant le chargement du code initialement inutilisé à un moment ultérieur et en auditant votre site pour identifier le code inutilisé que vous pouvez supprimer.
S'agissait-il d'un problème survenu après le chargement de la page ?
Bien que les retards de saisie se produisent souvent pendant le chargement d'une page, ils peuvent tout aussi bien se produire après le chargement d'une page, pour une raison totalement différente. Les causes courantes des retards d'entrée après le chargement de la page peuvent être un code qui s'exécute régulièrement en raison d'un appel setInterval
précédent, ou même des rappels d'événements qui ont été mis en file d'attente pour s'exécuter plus tôt et qui sont toujours en cours de traitement.
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {inputDelay} = attribution; // 125.59439536
// Get the longest script from the first LoAF entry:
const loaf = attribution.longAnimationFrameEntries[0];
const script = loaf?.scripts.sort((a, b) => b.duration - a.duration)[0];
if (script) {
const {invokerType} = script; // 'user-callback'
const {sourceURL} = script; // 'https://example.com/app.js'
const {sourceCharPosition} = script; // 83
const {sourceFunctionName} = script; // 'update'
}
});
Comme c'est le cas pour le dépannage des valeurs de durée de traitement élevées, des retards d'entrée élevés en raison des causes mentionnées précédemment vous fourniront des données détaillées d'attribution de script. Cependant, le type d'appelant change en fonction de la nature de la tâche qui a retardé l'interaction :
'user-callback'
indique que la tâche bloquante provient desetInterval
,setTimeout
ou mêmerequestAnimationFrame
.'event-listener'
indique que la tâche bloquante provient d'une entrée précédente mise en file d'attente et toujours en cours de traitement.'resolve-promise'
et'reject-promise'
signifient que la tâche bloquante provient d'un travail asynchrone lancé précédemment, et qu'elle a été résolue ou refusée au moment où l'utilisateur a tenté d'interagir avec la page, ce qui a retardé l'interaction.
Dans tous les cas, les données d'attribution de script vous indiqueront où commencer à chercher et si le délai de saisie était dû à votre propre code ou à celui d'un script tiers.
Retards de présentation importants
Les délais de présentation sont la dernière étape d'une interaction. Ils commencent lorsque les gestionnaires d'événements de l'interaction se terminent, jusqu'au moment où le frame suivant a été peint. Ils se produisent lorsque le travail effectué dans un gestionnaire d'événements en raison d'une interaction modifie l'état visuel de l'interface utilisateur. Comme pour les durées de traitement et les délais d'entrée, la bibliothèque web-Vitals peut vous indiquer le délai de présentation d'une interaction:
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {presentationDelay} = attribution; // 113.32307691
});
Si vous enregistrez ces données et que vous constatez des délais de présentation élevés pour les interactions contribuant à l'INP de votre site Web, les causes peuvent varier, mais voici quelques éléments à surveiller.
Travail de style et de mise en page coûteux
Les retards de présentation longs peuvent s'avérer coûteux en termes de recalcul de style et de mise en page. Cette opération peut avoir plusieurs causes, y compris les sélecteurs CSS complexes et les tailles de DOM volumineuses. Vous pouvez mesurer la durée de ce travail avec les temps de chargement de l'élément affichés dans la bibliothèque Web Vitals :
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {presentationDelay} = attribution; // 113.32307691
// Get the longest script from the last LoAF entry:
const loaf = attribution.longAnimationFrameEntries.at(-1);
const script = loaf?.scripts.sort((a, b) => b.duration - a.duration)[0];
// Get necessary timings:
const {startTime} = loaf; // 2120.5
const {duration} = loaf; // 1002
// Figure out the ending timestamp of the frame (approximate):
const endTime = startTime + duration; // 3122.5
// Get the start timestamp of the frame's style/layout work:
const {styleAndLayoutStart} = loaf; // 3011.17692309
// Calculate the total style/layout duration:
const styleLayoutDuration = endTime - styleAndLayoutStart; // 111.32307691
if (script) {
// Get attribution for the event handler that triggered
// the long-running style and layout operation:
const {invokerType} = script; // 'event-listener'
const {invoker} = script; // 'BUTTON#update.onclick'
const {sourceURL} = script; // 'https://example.com/app.js'
const {sourceCharPosition} = script; // 83
const {sourceFunctionName} = script; // 'update'
}
});
LoAF ne vous indiquera pas la durée du travail de style et de mise en page pour un cadre, mais il vous indiquera quand il a commencé. Avec cet horodatage de début, vous pouvez utiliser d'autres données de la LoAF pour calculer une durée précise de ce travail en déterminant l'heure de fin du frame et en soustrayant l'horodatage de début du travail de style et de mise en page de cette valeur.
Rappels requestAnimationFrame
de longue durée
L'une des causes potentielles de longs retards de présentation est un travail excessif effectué dans un rappel requestAnimationFrame
. Le contenu de ce rappel est exécuté une fois l'exécution des gestionnaires d'événements terminée, mais juste avant le recalcul des styles et le travail de mise en page.
Ces rappels peuvent prendre un temps considérable si le travail effectué en leur sein est complexe. Si vous pensez que des valeurs de délai de présentation élevées sont dues à un travail que vous effectuez avec requestAnimationFrame
, vous pouvez utiliser les données LoAF affichées par la bibliothèque web-vitals pour identifier les scénarios suivants:
onINP(({name, value, attribution}) => {
const {presentationDelay} = attribution; // 543.1999999880791
// Get the longest script from the last LoAF entry:
const loaf = attribution.longAnimationFrameEntries.at(-1);
const script = loaf?.scripts.sort((a, b) => b.duration - a.duration)[0];
// Get the render start time and when style and layout began:
const {renderStart} = loaf; // 2489
const {styleAndLayoutStart} = loaf; // 2989.5999999940395
// Calculate the `requestAnimationFrame` callback's duration:
const rafDuration = styleAndLayoutStart - renderStart; // 500.59999999403954
if (script) {
// Get attribution for the event handler that triggered
// the long-running requestAnimationFrame callback:
const {invokerType} = script; // 'user-callback'
const {invoker} = script; // 'FrameRequestCallback'
const {sourceURL} = script; // 'https://example.com/app.js'
const {sourceCharPosition} = script; // 83
const {sourceFunctionName} = script; // 'update'
}
});
Si vous constatez qu'une partie importante du délai de présentation est consacrée à un rappel requestAnimationFrame
, assurez-vous que le travail que vous effectuez dans ces rappels est limité à des tâches qui entraînent une actualisation réelle de l'interface utilisateur. Toute autre tâche qui ne touche pas au DOM ni ne met à jour les styles retardera inutilement la peinture du prochain frame. Faites donc attention !
Conclusion
Les données sur le terrain sont la meilleure source d'informations à laquelle vous pouvez vous référer pour comprendre quelles interactions sont problématiques pour les utilisateurs réels sur le terrain. En vous appuyant sur des outils de collecte de données sur le terrain tels que la bibliothèque JavaScript Web Vitals (ou un fournisseur de RUM), vous pouvez identifier plus précisément les interactions les plus problématiques, puis les reproduire en laboratoire et les corriger.
Image principale tirée de Unsplash, de Federico Respini.