Métriques personnalisées

Le fait de disposer de métriques universelles et centrées sur l'utilisateur, que vous pouvez mesurer sur n'importe quel site Web, peut s'avérer très utile pour comprendre l'expérience des utilisateurs sur le Web et pour comparer votre site à celui de vos concurrents. Toutefois, dans de nombreux cas, vous devez mesurer plus que les métriques universelles afin de capturer l'expérience complète pour votre site spécifique.

Les métriques personnalisées vous permettent de mesurer des aspects de l'expérience sur votre site qui peuvent ne s'appliquer qu'à votre site, tels que:

  • Temps nécessaire à une application monopage (SPA) pour passer d'une "page" à une autre.
  • Temps nécessaire pour qu'une page affiche les données extraites d'une base de données pour les utilisateurs connectés.
  • Temps nécessaire à une application rendue côté serveur pour s'hydrater.
  • Taux de succès de la mise en cache pour les ressources chargées par les visiteurs connus.
  • Latence des événements de clic ou de clavier dans un jeu.

API permettant de mesurer les métriques personnalisées

Jusqu'à présent, les développeurs Web ne disposaient pas de nombreuses API de bas niveau pour mesurer les performances. Par conséquent, ils ont dû recourir à des techniques de piratage pour évaluer les performances d'un site. Par exemple, vous pouvez déterminer si le thread principal est bloqué par des 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 considérablement plus long que la fréquence d'images de l'écran, vous pouvez signaler cela comme une tâche longue.

Toutefois, ce type de piratage peut affecter les performances de votre site, par exemple en épuisant la batterie de l'appareil. Si vos techniques de mesure des performances génèrent elles-mêmes des problèmes de performances, les données obtenues ne seront pas exactes. Par conséquent, nous vous recommandons d'utiliser l'une des API suivantes pour créer des métriques personnalisées.

API Performance Observer

Navigateurs pris en charge

  • 52
  • 79
  • 57
  • 11

Source

L'API Performance Observer est le mécanisme qui collecte et affiche les données de toutes les autres API de performances décrites sur cette page. Comprendre qu'il est essentiel d'obtenir de bonnes données.

Vous pouvez utiliser PerformanceObserver pour vous abonner de manière passive à des é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'interfèrent généralement pas avec les performances de la page.

Lorsque vous créez un PerformanceObserver, transmettez-lui un rappel qui s'exécute chaque fois que de nouvelles entrées de performances sont envoyées. Utilisez ensuite la méthode observe() pour indiquer à l'observateur les types d'entrées à écouter comme suit:

// Catch errors that some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  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'});
} catch (e) {
  // Do nothing if the browser doesn't support this API.
}

Les sections suivantes répertorient tous les types d'entrées que vous pouvez observer. Dans les navigateurs plus récents, vous pouvez également inspecter les types d'entrées disponibles à l'aide de 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 que les entrées au fur et à mesure qu'elles se produisent. Cela peut entraîner des problèmes si vous souhaitez charger votre code d'analyse des performances de manière différée afin qu'il ne bloque pas les ressources de priorité supérieure.

Pour obtenir l'historique des entrées, appelez observe avec l'option buffered définie sur true. La première fois que votre rappel PerformanceObserver est appelé, le navigateur inclut ensuite les entrées historiques de son tampon d'entrée des performances.

po.observe({
  type: 'some-entry-type',
  buffered: true,
});

Anciennes API Performance à éviter

Avant l'API Performance Observer, les développeurs pouvaient accéder aux entrées de performances à l'aide des méthodes suivantes définies sur l'objet performance. Nous vous déconseillons de les utiliser, car ils ne vous permettent pas d'écouter de nouvelles entrées.

En outre, de nombreuses nouvelles API (telles que les tâches longues) ne sont pas exposées par l'objet performance, mais uniquement par PerformanceObserver. Par conséquent, à 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

L'API User Timing est une API de mesure à usage général pour les métriques temporelles. Elle vous permet de marquer arbitrairement des points dans le temps, puis de mesurer la durée entre ces marques ultérieurement.

// 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 est mieux intégrée aux outils de performances. Par exemple, les outils pour les développeurs Chrome permettent de visualiser les mesures du temps utilisateur dans le panneau "Performances". De nombreux fournisseurs de services 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, enregistrez un PerformanceObserver afin d'observer les entrées de type measure:

// Catch errors some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  // 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.
  po.observe({type: 'measure', buffered: true});
} catch (e) {
  // Do nothing if the browser doesn't support this API.
}

API Long Tasks

Navigateurs pris en charge

  • 58
  • 79
  • x
  • x

Source

L'API Long Tasks permet de déterminer 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 toutes les tâches qui s'exécutent pendant plus de 50 millisecondes (ms).

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 sont basées sur l'API Long Tasks (telles que Time to Interactive (TTI) et Total Blocking Time (TBT)).

Pour déterminer à quel moment les tâches longues se produisent, enregistrez un PerformanceObserver afin d'observer les entrées de type longtask:

// Catch errors since some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  // 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});
} catch (e) {
  // Do nothing if the browser doesn't support this API.
}

API Element Timing

Navigateurs pris en charge

  • 77
  • 79
  • x
  • x

Source

La métrique LCP (Largest Contentful Paint) est utile pour savoir quand le plus grand bloc d'image ou de texte de votre page est affiché à l'écran, mais que vous souhaitez dans certains cas mesurer le délai d'affichage d'un autre élément.

Dans ce 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 contenu. 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 observer le type d'entrée element.

<img elementtiming="hero-image" />
<p elementtiming="important-paragraph">This is text I care about.</p>
...
<script>
// Catch errors since some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  // Create the performance observer.
  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});
} catch (e) {
  // Do nothing if the browser doesn't support this API.
}
</script>

API Event Timing

La métrique FID (First Input Delay) mesure le délai entre le moment où un utilisateur interagit pour la première fois avec une page et le moment où le navigateur peut commencer à traiter les gestionnaires d'événements en réponse à cette interaction. Toutefois, dans certains cas, il peut également être utile de mesurer le temps de traitement des événements lui-même.

Cela est possible à l'aide de l'API Event Timing, qui, en plus de mesurer le FID, expose un certain nombre d'horodatages dans le cycle de vie des événements, y compris:

  • startTime : heure à laquelle le navigateur reçoit l'événement.
  • processingStart : moment auquel le navigateur peut commencer à traiter les gestionnaires d'événements pour l'événement.
  • processingEnd : heure à laquelle le navigateur a terminé d'exécuter tout le code synchrone lancé par les gestionnaires d'événements pour cet événement.
  • duration : délai (arrondi à 8 ms pour des raisons de sécurité) entre le moment où le navigateur reçoit l'événement et celui où il est en mesure de peindre le frame suivant après l'exécution de tout le code synchrone lancé par les gestionnaires d'événements.

L'exemple suivant montre comment utiliser ces valeurs pour créer des mesures personnalisées:

// Catch errors some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  const po = new PerformanceObserver((entryList) => {
    const firstInput = entryList.getEntries()[0];

    // Measure First Input Delay (FID).
    const firstInputDelay = firstInput.processingStart - firstInput.startTime;

    // Measure the time it takes to run all event handlers
    // Doesn't include work scheduled asynchronously using methods like
    // `requestAnimationFrame()` or `setTimeout()`.
    const firstInputProcessingTime = firstInput.processingEnd - firstInput.processingStart;

    // Measure the entire duration of the event, from when input is received by
    // the browser until the next frame can be painted after processing all
    // event handlers.
    // Doesn't include work scheduled asynchronously using
    // `requestAnimationFrame()` or `setTimeout()`.
    // For security reasons, this value is rounded to the nearest 8 ms.
    const firstInputDuration = firstInput.duration;

    // Log these values to the console.
    console.log({
      firstInputDelay,
      firstInputProcessingTime,
      firstInputDuration,
    });
  });

  po.observe({type: 'first-input', buffered: true});
} catch (error) {
  // Do nothing if the browser doesn't support this API.
}

API Resource Timing

L'API Resource Timing permet aux développeurs d'obtenir 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 que cela soit abondant). Vous pouvez également accéder aux données suivantes:

  • initiatorType : mode de récupération de la ressource, par exemple à partir d'un tag <script> ou <link>, ou à partir de fetch()
  • nextHopProtocol : protocole utilisé pour récupérer la ressource, par exemple h2 ou quic.
  • encodedBodySize et decodedBodySize]: la taille de la ressource dans sa forme encodée ou décodée (respectivement).
  • transferSize : taille de la ressource qui a été réellement transférée sur le réseau. Lorsque les ressources sont traitées à l'aide du cache, cette valeur peut être nettement inférieure à encodedBodySize. Dans certains cas, elle peut être nulle si aucune revalidation du cache n'est requise.

Vous pouvez utiliser la propriété transferSize des entrées de codes temporels des ressources pour mesurer une métrique de taux d'accès au cache ou de taille totale de la ressource mise en cache. Cela 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é exécutée ou non à l'aide du cache:

// Catch errors some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  // Create the performance observer.
  const po = new PerformanceObserver((list) => {
    for (const entry of list.getEntries()) {
      // If transferSize is 0, the resource was fulfilled via the cache.
      console.log(entry.name, entry.transferSize === 0);
    }
  });
  // Start listening for `resource` entries to be dispatched.
  po.observe({type: 'resource', buffered: true});
} catch (e) {
  // Do nothing if the browser doesn't support this API.
}

Navigateurs pris en charge

  • 57
  • 12
  • 58
  • 15

Source

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 resource, mais il contient des informations supplémentaires spécifiques aux requêtes de navigation uniquement (par exemple, quand les événements DOMContentLoaded et load se déclenchent).

La métrique Time to First Byte (TTFB) suivie par de nombreux développeurs pour comprendre le temps de réponse du serveur est disponible via l'horodatage responseStart dans l'API Navigation Timing.

// Catch errors since  browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  // 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});
} catch (e) {
  // Do nothing if the browser doesn't support this API.
}

Le temps de démarrage des service workers pour les requêtes de navigation est une autre métrique dont peuvent se préoccuper les développeurs qui utilisent des service workers. Il s'agit du temps nécessaire au navigateur pour démarrer le thread de service worker avant de pouvoir commencer à intercepter les événements de récupération.

Le temps de démarrage du service worker pour une requête de navigation spécifiée peut être déterminé à partir du delta entre entry.responseStart et entry.workerStart, comme suit:

// Catch errors some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  // 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});
} catch (e) {
  // Do nothing if the browser doesn't support this API.
}

API Server Timing

L'API Server Timing vous permet de transmettre des données temporelles spécifiques à une requête de votre serveur au navigateur à l'aide d'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 de performances du serveur avec d'autres métriques commerciales mesurées par ces outils d'analyse.

Pour spécifier les données de temps de serveur dans vos réponses, utilisez l'en-tête de réponse Server-Timing. 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 sur les entrées resource ou navigation des API Resource Timing et Navigation Timing.

// Catch errors some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  // 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});
} catch (e) {
  // Do nothing if the browser doesn't support this API.
}