Découvrez comment identifier les interactions lentes dans les données de champ de votre site Web afin de trouver des opportunités d'améliorer son Interaction to Next Paint.
Les données réelles vous indiquent comment les utilisateurs réels perçoivent votre site Web. Il permet de détecter des problèmes que vous ne pouvez pas identifier uniquement à l'aide des données de laboratoire. En ce qui concerne l'Interaction to Next Paint (INP), les données de terrain sont essentielles pour identifier les interactions lentes et fournissent des indices essentiels pour vous aider à les corriger.
Dans ce guide, vous allez apprendre à évaluer rapidement l'INP de votre site Web à l'aide des données réelles du rapport sur l'expérience utilisateur de Chrome (CrUX) pour déterminer si votre site Web 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 de terrain concernant les interactions lentes sur votre site Web.
Commencez par utiliser 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 réelles auprès d'utilisateurs Chrome réels qui ont accepté d'envoyer des données de télémétrie.
Les données CrUX sont présentées dans différents domaines, en fonction de la portée des informations que vous recherchez. CrUX peut fournir des données sur l'INP et d'autres Core Web Vitals pour :
- Pages individuelles et origines entières à l'aide de PageSpeed Insights.
- Types de pages. Par exemple, de nombreux sites d'e-commerce ont des types de pages "Page produit détaillée" et "Page de liste de produits". 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 pour vérifier vos valeurs INP pour les dimensions mobile et ordinateur.
Ces données sont utiles, car elles vous indiquent si vous rencontrez un problème. En revanche, CrUX ne peut pas vous dire ce qui cause les problèmes. Il existe de nombreuses solutions de surveillance des utilisateurs réels (RUM, Real User Monitoring) qui vous aideront à collecter vos propres données de terrain auprès des utilisateurs de votre site Web pour vous aider à répondre à cette question. L'une d'elles consiste à collecter vous-même ces données de terrain à l'aide de la bibliothèque JavaScript web-vitals.
Collecter des données de 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 de terrain auprès des utilisateurs de votre site Web. 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 en disent pas beaucoup plus que CrUX. C'est là qu'intervient la compilation d'attribution de la bibliothèque web-vitals.
Allez plus loin avec la compilation d'attribution de la bibliothèque web-vitals
La version d'attribution de la bibliothèque web-vitals affiche des données supplémentaires que vous pouvez obtenir auprès des utilisateurs sur le terrain pour vous aider à mieux résoudre les problèmes d'interactions qui affectent l'INP de votre site Web. Ces données sont accessibles via l'objet attribution exposé 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, la compilation d'attribution fournit de nombreuses données qui peuvent vous aider à comprendre les raisons de la lenteur des interactions, 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 longtemps ?"
- "Le démarrage du code du gestionnaire d'événements d'interaction a-t-il été retardé ? Si oui, que se passait-il d'autre sur le thread principal à ce moment-là ?"
- "L'interaction a-t-elle entraîné un travail de rendu important 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 et qui peuvent vous aider à identifier certaines causes générales de la lenteur des interactions sur votre site Web :
Clé d'objet attribution
|
Données |
|---|---|
interactionTarget
|
Sélecteur CSS pointant vers l'élément qui a produit la valeur INP de la page (par exemple, button#save).
|
interactionType
|
Type d'interaction (clics, appuis ou saisies au clavier). |
inputDelay*
|
Le délai de réponse à l'entrée utilisateur de l'interaction. |
processingDuration*
|
Temps écoulé entre le moment où le premier écouteur d'événements a commencé à s'exécuter en réponse à l'interaction de l'utilisateur et le moment où le traitement de tous les écouteurs d'événements est terminé. |
presentationDelay*
|
Le délai de présentation de l'interaction, qui commence à la fin des gestionnaires d'événements et se termine au moment où l'image suivante est affichée. |
longAnimationFrameEntries*
|
Entrées du LoAF associées à l'interaction. Pour en savoir plus, consultez la section suivante. |
À partir de la version 4 de la bibliothèque web-vitals, vous pouvez obtenir des informations encore plus détaillées sur les interactions problématiques grâce aux données qu'elle fournit avec les répartitions des phases 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 des données de champ est une tâche difficile. Toutefois, grâce aux données de LoAF, il est désormais possible d'obtenir de meilleures informations sur les causes des interactions lentes, car 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, plus important encore, l'origine 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 données clés que vous pouvez trouver dans chaque entrée LoAF :
| Clé d'objet de l'entrée LoAF | Données |
|---|---|
duration
|
Durée du frame d'animation long, jusqu'à la fin de la mise en page, mais sans inclure la peinture ni la composition. |
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écutant du code JavaScript, ainsi que toute tâche de rendu longue ultérieure dans le frame. |
firstUIEventTimestamp
|
Code temporel de la mise en file d'attente de l'événement pendant l'image. Utile pour déterminer le début du délai d'entrée d'une interaction. |
startTime
|
Code temporel de début du frame. |
renderStart
|
Début du rendu du frame. Cela inclut tous les rappels requestAnimationFrame (et les rappels ResizeObserver, le cas échéant), mais potentiellement avant le début de tout travail de style/mise en page.
|
styleAndLayoutStart
|
Lorsque le style/la mise en page sont appliqués au frame. Peut être utile pour déterminer la durée du travail de style/mise en page en tenant compte d'autres codes temporels disponibles. |
scripts
|
Tableau d'éléments contenant des informations sur l'attribution des scripts contribuant à l'INP de la page. |
blockingDuration).
Toutes ces informations peuvent vous en dire beaucoup sur ce qui ralentit une interaction, mais 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. Les appelants peuvent être des valeurs telles que 'IMG#id.onload', 'Window.requestAnimationFrame' ou 'Response.json.then'. |
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 le frame d'animation long. |
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 responsable de l'interaction lente et sur la manière dont 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 va maintenant vous expliquer comment utiliser les données LoAF affichées dans la bibliothèque web-vitals pour déterminer certaines causes d'interactions lentes.
Longues durées de traitement
La durée de traitement d'une interaction correspond au temps nécessaire pour que les rappels de gestionnaire d'événements enregistrés de l'interaction s'exécutent jusqu'à la fin, ainsi que tout ce qui peut se produire entre eux. Les durées de traitement élevées sont signalées par la bibliothèque web-vitals :
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {processingDuration} = attribution; // 512.5
});
Il est naturel de penser que la cause principale d'une interaction lente est que le code de votre gestionnaire d'événements a mis trop de temps à s'exécuter, mais ce n'est pas toujours le cas. Une fois que vous avez confirmé qu'il s'agit du problème, vous pouvez approfondir vos recherches à l'aide des 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.toSorted((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 précise 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 du caractère 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 d'une valeur inestimable. Vous n'avez plus besoin de chercher exactement quelle interaction (ou quel gestionnaire d'événements) est 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 votre code est responsable ou non. Pour le code que vous contrôlez, vous devez optimiser les tâches longues.
Longs délais de réponse à l'entrée utilisateur
Bien que les gestionnaires d'événements de longue durée soient courants, d'autres parties de l'interaction doivent être prises en compte. Une partie se produit avant la durée de traitement, appelée délai d'entrée. Il s'agit du temps qui s'écoule 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 compilation d'attribution de la bibliothèque web-vitals peut vous indiquer la durée du délai d'entrée d'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é ce délai d'entrée élevé. Cela se résume souvent à déterminer si l'interaction s'est produite pendant le chargement de la page ou après.
Est-ce que c'était pendant le chargement de la page ?
Le thread principal est souvent le plus occupé lors du chargement d'une page. Pendant ce temps, toutes sortes de tâches sont mises en file d'attente et traitées. Si l'utilisateur tente d'interagir avec la page pendant que tout ce travail est en cours, l'interaction peut être retardée. Les pages qui chargent beaucoup de code JavaScript peuvent lancer la compilation et l'évaluation des scripts, ainsi que l'exécution des fonctions qui préparent une page pour les interactions des utilisateurs. Ce travail peut être gênant si l'utilisateur interagit pendant 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.toSorted((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 délais d'entrée élevés et des types d'appelants 'classic-script' ou 'module-script', on peut dire que les scripts de votre site mettent beaucoup de temps à s'évaluer et bloquent le thread principal suffisamment longtemps pour retarder les interactions. Vous pouvez réduire ce temps de blocage en divisant vos scripts en bundles plus petits, en différant le chargement du code initialement inutilisé et en auditant votre site pour identifier le code inutilisé que vous pouvez supprimer complètement.
Après le chargement de la page ?
Bien que les délais d'entrée 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 délais d'entrée après le chargement de la page peuvent être du code qui s'exécute régulièrement en raison d'un appel setInterval antérieur, 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.toSorted((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 pour le dépannage des valeurs de durée de traitement élevées, les retards d'entrée élevés dus aux causes mentionnées précédemment vous fourniront des données détaillées sur l'attribution des scripts. Toutefois, le type d'appelant change en fonction de la nature du travail qui a retardé l'interaction :
'user-callback'indique que la tâche bloquante provenait desetInterval,setTimeoutou mêmerequestAnimationFrame.'event-listener'indique que la tâche bloquante provenait d'une entrée antérieure qui était en file d'attente et toujours en cours de traitement.'resolve-promise'et'reject-promise'signifient que la tâche bloquante provenait d'un travail asynchrone qui a été lancé plus tôt, puis résolu ou rejeté 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 du script vous donneront une idée de l'endroit où commencer à chercher et vous indiqueront si le délai d'entrée est dû à votre propre code ou à celui d'un script tiers.
Longs délais de présentation
Les délais de présentation constituent la dernière étape d'une interaction. Ils commencent lorsque les gestionnaires d'événements de l'interaction se terminent, jusqu'au moment où l'image suivante est affichée. Ils se produisent lorsque le travail 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 la durée du 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 causes à surveiller.
Travail de style et de mise en page coûteux
Les longs délais de présentation peuvent être dus à un recalcul de style et à une mise en page coûteux, qui découlent de plusieurs causes, y compris des sélecteurs CSS complexes et des tailles de DOM importantes. Vous pouvez mesurer la durée de ce travail à l'aide des codes temporels LoAF 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.toSorted((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 indique pas la durée du travail de style et de mise en page pour un frame, mais il vous indique quand il a commencé. Avec ce code temporel de départ, vous pouvez utiliser d'autres données de LoAF pour calculer une durée précise de ce travail en déterminant l'heure de fin du frame et en soustrayant le code temporel de début du travail de style et de mise en page.
Rappels requestAnimationFrame de longue durée
Une cause potentielle de longs délais de présentation est un travail excessif effectué dans un rappel requestAnimationFrame. Le contenu de ce rappel est exécuté une fois que les gestionnaires d'événements ont terminé leur exécution, mais juste avant le recalcul du style et le travail de mise en page.
Ces rappels peuvent prendre beaucoup de temps si le travail effectué est complexe. Si vous pensez que les valeurs de délai de présentation élevées sont dues au travail que vous effectuez avec requestAnimationFrame, vous pouvez utiliser les données LoAF fournies par la bibliothèque web-vitals pour identifier ces scénarios :
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.toSorted((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 part importante du délai de présentation est consacrée à un rappel requestAnimationFrame, assurez-vous que le travail que vous effectuez dans ces rappels se limite à l'exécution d'une tâche qui entraîne une mise à jour réelle de l'interface utilisateur. Toute autre tâche qui ne touche pas au DOM ni ne met à jour les styles retardera inutilement l'affichage de l'image suivante. Soyez donc prudent.
Conclusion
Les données de terrain sont la meilleure source d'informations à laquelle vous pouvez faire appel pour comprendre quelles interactions posent problème aux utilisateurs réels sur le terrain. En vous appuyant sur des outils de collecte de données de terrain tels que la bibliothèque JavaScript web-vitals (ou un fournisseur de RUM), vous pouvez identifier plus facilement les interactions les plus problématiques, puis reproduire les interactions problématiques en laboratoire et les corriger.