Les métriques centrées sur l'utilisateur présentent de nombreux avantages, que vous pouvez mesurer de manière universelle sur n'importe quel site Web. Ces métriques vous permettent d'effectuer les opérations suivantes:
- Comprendre l'expérience des utilisateurs réels sur le Web dans son ensemble.
- Comparez votre site à celui d'un concurrent.
- Effectuez le suivi des données utiles et exploitables dans vos outils d'analyse sans avoir à écrire de code personnalisé.
Les métriques universelles constituent un bon point de référence. Toutefois, dans de nombreux cas, vous devez mesurer plus que ces métriques afin de capturer l'expérience complète sur votre site en particulier.
Les métriques personnalisées vous permettent d'évaluer des aspects de l'expérience utilisateur qui peuvent ne s'appliquer qu'à votre site. En voici quelques exemples:
- Le temps nécessaire pour qu'une application monopage (SPA) passe d'une "page" à une autre à un autre.
- Temps nécessaire pour qu'une page affiche les données extraites d'une base de données pour les utilisateurs connectés.
- Le temps nécessaire à l'hydratation d'une application rendue côté serveur (SSR)
- Taux de succès de cache pour les ressources chargées par les visiteurs connus.
- Latence des événements de clic ou de clavier dans un jeu.
API pour mesurer des métriques personnalisées
Par le passé, les développeurs Web n'avaient pas beaucoup d'API de bas niveau pour mesurer les performances. Ils ont donc dû recourir au piratage pour déterminer si un site était performant.
Par exemple, il est possible de déterminer si le thread principal est bloqué en raison de tâches JavaScript de longue durée en exécutant une boucle requestAnimationFrame
et en calculant le delta entre chaque frame. Si le delta est nettement plus long que la fréquence d'images de l'écran, vous pouvez le signaler comme une tâche longue. Ces techniques ne sont toutefois pas recommandées, car elles affectent les performances elles-mêmes (en déchargeant la batterie, par exemple).
Pour mesurer efficacement les performances, vous devez d'abord vous assurer que vos techniques de mesure des performances n'entraînent pas elles-mêmes de problèmes de performances. Par conséquent, pour toutes les métriques personnalisées que vous mesurez sur votre site, il est préférable d'utiliser l'une des API suivantes, si possible.
API Performance Observer
Navigateurs pris en charge
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
L'API Performance Observer est le mécanisme qui collecte et affiche les données de toutes les autres API de performances abordées sur cette page. Il est essentiel de le comprendre pour obtenir des données de qualité.
Vous pouvez utiliser PerformanceObserver
pour vous abonner de manière passive aux événements liés aux performances. Cela permet aux rappels d'API de se déclencher pendant les périodes d'inactivité, ce qui signifie qu'ils n'affectent généralement pas les performances de la page.
Pour créer un PerformanceObserver
, transmettez-lui un rappel à exécuter chaque fois que de nouvelles entrées de performances sont envoyées. Ensuite, vous indiquez à l'observateur les types d'entrées à écouter à l'aide de la méthode observe()
:
const po = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
// Log the entry and all associated details.
console.log(entry.toJSON());
}
});
po.observe({type: 'some-entry-type'});
Les sections suivantes répertorient les différents types d'entrées disponibles à observer. Toutefois, dans les navigateurs les plus récents, vous pouvez inspecter les types d'entrées disponibles via la propriété statique PerformanceObserver.supportedEntryTypes
.
Observer les entrées qui se sont déjà produites
Par défaut, les objets PerformanceObserver
ne peuvent observer les entrées que lorsqu'elles se produisent. Cela peut poser des problèmes si vous souhaitez effectuer un chargement différé de votre code d'analyse des performances afin de ne pas bloquer les ressources prioritaires.
Pour obtenir les entrées historiques (après qu'elles se sont produites), définissez l'option buffered
sur true
lorsque vous appelez observe()
. Le navigateur inclut les entrées historiques de son tampon d'entrée des performances la première fois que votre rappel PerformanceObserver
est appelé, jusqu'à la taille maximale de la mémoire tampon pour ce type.
po.observe({
type: 'some-entry-type',
buffered: true,
});
Anciennes API de performance à éviter
Avant l'API Performance Observer, les développeurs pouvaient accéder aux entrées de performances à l'aide des trois méthodes suivantes définies sur l'objet performance
:
Bien que ces API soient toujours compatibles, leur utilisation n'est pas recommandée, car elles ne vous permettent pas d'écouter quand de nouvelles entrées sont émises. De plus, de nombreuses nouvelles API (telles que largest-contentful-paint
) ne sont pas exposées via l'objet performance
. Elles ne le sont que via PerformanceObserver
.
À moins que vous n'ayez spécifiquement besoin d'une compatibilité avec Internet Explorer, il est préférable d'éviter ces méthodes dans votre code et d'utiliser PerformanceObserver
à l'avenir.
API User Timing
Navigateurs pris en charge
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
L'API User Timing est un outil à usage général de mesure pour les métriques temporelles. Elle vous permet de marquer arbitrairement des points dans et mesurer plus tard la durée entre ces deux repères.
// Record the time immediately before running a task.
performance.mark('myTask:start');
await doMyTask();
// Record the time immediately after running a task.
performance.mark('myTask:end');
// Measure the delta between the start and end of the task
performance.measure('myTask', 'myTask:start', 'myTask:end');
Bien que des API telles que Date.now()
ou performance.now()
offrent des fonctionnalités similaires, l'API User Timing offre l'avantage suivant : elle s'intègre bien aux outils de gestion des performances. Par exemple, les outils pour les développeurs Chrome permettent de visualiser les mesures du temps utilisateur dans le panneau "Performances". De plus, de nombreux fournisseurs de solutions d'analyse suivent automatiquement toutes les mesures que vous effectuez et envoient les données de durée à leur backend d'analyse.
Pour générer des rapports sur les mesures du temps utilisateur, vous pouvez utiliser PerformanceObserver et vous inscrire pour observer des entrées de type measure
:
// Create the performance observer.
const po = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
// Log the entry and all associated details.
console.log(entry.toJSON());
}
});
// Start listening for `measure` entries to be dispatched.
po.observe({type: 'measure', buffered: true});
API Long Tasks
Navigateurs pris en charge
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
L'API Long Tasks permet de savoir quand le thread principal du navigateur est bloqué suffisamment longtemps pour affecter la fréquence d'images ou la latence d'entrée. L'API signale les tâches exécutées pendant plus de 50 millisecondes.
<ph type="x-smartling-placeholder">Chaque fois que vous devez exécuter du code coûteux, ou charger et exécuter des scripts volumineux, il est utile de vérifier si ce code bloque le thread principal. En fait, de nombreuses métriques de niveau supérieur reposent sur l'API Long Tasks elle-même (telles que Time to Interactive (TTI) et Total Blocking Time (TBT)).
Pour déterminer à quel moment les longues tâches se produisent, vous pouvez utiliser PerformanceObserver et vous enregistrer pour observer des entrées de type longtask
:
// Create the performance observer.
const po = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
// Log the entry and all associated details.
console.log(entry.toJSON());
}
});
// Start listening for `longtask` entries to be dispatched.
po.observe({type: 'longtask', buffered: true});
API Long Animation Frames
Navigateurs pris en charge
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
L'API Long Animation Frames est une nouvelle itération de l'API Long Tasks. Elle s'intéresse aux longues images (plutôt qu'aux tâches longues) de plus de 50 millisecondes. Cela permet de remédier à certains problèmes de l'API Long Tasks, y compris une meilleure attribution et l'étendue des retards potentiellement problématiques.
Pour déterminer quand des frames longs se produisent, vous pouvez utiliser PerformanceObserver et vous enregistrer pour observer des entrées de type long-animation-frame
:
// Create the performance observer.
const po = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
// Log the entry and all associated details.
console.log(entry.toJSON());
}
});
// Start listening for `long-animation-frame` entries to be dispatched.
po.observe({type: 'long-animation-frame', buffered: true});
API Element Timing
Navigateurs pris en charge
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
La métrique LCP (Largest Contentful Paint) est utile pour savoir à quel moment la plus grande image ou le plus grand bloc de texte a été affiché à l'écran, mais dans certains cas, vous pouvez mesurer le délai d'affichage d'un autre élément.
Dans ces cas, utilisez l'API Element Timing. L'API LCP repose en réalité sur l'API Element Timing et ajoute des rapports automatiques sur le plus grand élément Contentful. Toutefois, vous pouvez également générer des rapports sur d'autres éléments en leur ajoutant explicitement l'attribut elementtiming
et en enregistrant un PerformanceObserver pour surveiller le type d'entrée element
.
<img elementtiming="hero-image" />
<p elementtiming="important-paragraph">This is text I care about.</p>
<!-- ... -->
<script>
const po = new PerformanceObserver((entryList) => {
for (const entry of entryList.getEntries()) {
// Log the entry and all associated details.
console.log(entry.toJSON());
}
});
// Start listening for `element` entries to be dispatched.
po.observe({type: 'element', buffered: true});
</script>
API Event Timing
Navigateurs pris en charge
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
La métrique Interaction to Next Paint (INP) évalue la réactivité globale de la page en observant toutes les interactions liées aux clics, aux appuis et au clavier tout au long de la page. L'INP d'une page est le plus souvent l'interaction qui a pris le plus de temps, entre le moment où l'utilisateur a initié l'interaction jusqu'au moment où le navigateur affiche le frame suivant montrant le résultat visuel de l'entrée utilisateur.
La métrique INP est possible grâce à l'API Event Timing. Cette API expose un certain nombre de codes temporels qui surviennent pendant le cycle de vie de l'événement, y compris:
startTime
: heure à laquelle le navigateur reçoit l'événement.processingStart
: heure à laquelle le navigateur peut commencer à traiter les gestionnaires d'événements pour l'événement.processingEnd
: heure à laquelle le navigateur termine l'exécution de tout le code synchrone initié à partir des gestionnaires d'événements pour cet événement.duration
: délai (arrondi à 8 millisecondes pour des raisons de sécurité) entre le moment où le navigateur reçoit l'événement et le moment où il peut afficher le frame suivant après la fin de l'exécution de tout le code synchrone lancé à partir des gestionnaires d'événements.
L'exemple suivant montre comment utiliser ces valeurs pour créer des mesures personnalisées:
const po = new PerformanceObserver((entryList) => {
// Get the last interaction observed:
const entries = Array.from(entryList.getEntries()).forEach((entry) => {
// Get various bits of interaction data:
const inputDelay = entry.processingStart - entry.startTime;
const processingTime = entry.processingEnd - entry.processingStart;
const presentationDelay = entry.startTime + entry.duration - entry.processingEnd;
const duration = entry.duration;
const eventType = entry.name;
const target = entry.target || "(not set)"
console.log("----- INTERACTION -----");
console.log(`Input delay (ms): ${inputDelay}`);
console.log(`Event handler processing time (ms): ${processingTime}`);
console.log(`Presentation delay (ms): ${presentationDelay}`);
console.log(`Total event duration (ms): ${duration}`);
console.log(`Event type: ${eventType}`);
console.log(target);
});
});
// A durationThreshold of 16ms is necessary to include more
// interactions, since the default is 104ms. The minimum
// durationThreshold is 16ms.
po.observe({type: 'event', buffered: true, durationThreshold: 16});
API Resource Timing
Navigateurs pris en charge
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
L'API Resource Timing fournit aux développeurs des informations détaillées sur le chargement des ressources d'une page spécifique. Malgré le nom de l'API, les informations qu'elle fournit ne se limitent pas aux données temporelles (bien qu'il y en ait beaucoup). Les autres données auxquelles vous pouvez accéder incluent:
initiatorType
: manière dont la ressource a été récupérée, par exemple à partir d'un tag<script>
ou<link>
, ou d'un appelfetch()
.nextHopProtocol
: protocole utilisé pour récupérer la ressource (par exempleh2
ouquic
).encodedBodySize
/decodedBodySize]: taille de la ressource sous sa forme encodée ou décodée (respectivement)transferSize
: taille de la ressource réellement transférée sur le réseau. Lorsque les ressources sont traitées par le cache, cette valeur peut être nettement inférieure àencodedBodySize
et, dans certains cas, être égale à zéro (si aucune revalidation du cache n'est requise).
Vous pouvez utiliser la propriété transferSize
des entrées de durée des ressources pour mesurer une métrique de taux de succès de cache ou de taille totale de la ressource mise en cache, ce qui peut être utile pour comprendre l'impact de votre stratégie de mise en cache des ressources sur les performances des visiteurs récurrents.
L'exemple suivant consigne toutes les ressources demandées par la page et indique si chaque ressource a été traitée ou non par le cache.
// Create the performance observer.
const po = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
// If transferSize is 0, the resource was fulfilled using the cache.
console.log(entry.name, entry.transferSize === 0);
}
});
// Start listening for `resource` entries to be dispatched.
po.observe({type: 'resource', buffered: true});
API Navigation Timing
Navigateurs pris en charge
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
L'API Navigation Timing est semblable à l'API Resource Timing, mais elle ne génère que des rapports sur les requêtes de navigation. Le type d'entrée navigation
est également semblable au type d'entrée resource
, mais il contient des informations supplémentaires spécifiques aux seules requêtes de navigation (par exemple, le déclenchement des événements DOMContentLoaded
et load
).
Une métrique que de nombreux développeurs suivent pour comprendre le temps de réponse du serveur (Time to First Byte (TTFB)) est disponible à l'aide de l'API Navigation Timing. Il s'agit en particulier de l'horodatage responseStart
de l'entrée.
// Create the performance observer.
const po = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
// If transferSize is 0, the resource was fulfilled using the cache.
console.log('Time to first byte', entry.responseStart);
}
});
// Start listening for `navigation` entries to be dispatched.
po.observe({type: 'navigation', buffered: true});
Le temps de démarrage du service worker pour les requêtes de navigation est une autre métrique qui peut intéresser les développeurs qui utilisent un service worker. Il s'agit du temps nécessaire au navigateur pour démarrer le thread de service worker avant de pouvoir commencer à intercepter des événements de récupération.
Le temps de démarrage du service worker pour une requête de navigation particulière peut être déterminé à partir du delta entre entry.responseStart
et entry.workerStart
.
// Create the performance observer.
const po = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
console.log('Service Worker startup time:',
entry.responseStart - entry.workerStart);
}
});
// Start listening for `navigation` entries to be dispatched.
po.observe({type: 'navigation', buffered: true});
API Server Timing
Navigateurs pris en charge
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
L'API Server Timing vous permet de transmettre des données temporelles spécifiques aux requêtes depuis votre serveur vers le navigateur via des en-têtes de réponse. Par exemple, vous pouvez indiquer le temps nécessaire pour rechercher des données dans une base de données pour une requête particulière, ce qui peut être utile pour déboguer les problèmes de performances causés par la lenteur du serveur.
Pour les développeurs qui font appel à des fournisseurs de solutions d'analyse tiers, l'API Server Timing est le seul moyen de corréler les données sur les performances du serveur avec d'autres métriques commerciales que ces outils d'analyse sont susceptibles de mesurer.
Pour spécifier des données de temps de serveur dans vos réponses, vous pouvez utiliser l'en-tête de réponse Server-Timing
. Voici un exemple.
HTTP/1.1 200 OK
Server-Timing: miss, db;dur=53, app;dur=47.2
Ensuite, à partir de vos pages, vous pouvez lire ces données dans les entrées resource
ou navigation
des API Resource Timing et Navigation Timing.
// Create the performance observer.
const po = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
// Logs all server timing data for this response
console.log('Server Timing', entry.serverTiming);
}
});
// Start listening for `navigation` entries to be dispatched.
po.observe({type: 'navigation', buffered: true});