--- title: Chronologie slug: Tools/Performance/Waterfall translation_of: Tools/Performance/Waterfall original_slug: Outils/Performance/Waterfall ---
{{ToolsSidebar}}

La chronologie vous donne des indications sur les opérations qu'effectue le navigateur lorsqu'il fait tourner une page web ou une application. Cet outil se base sur l'idée que les opérations qu'effectue un navigateur peuvent être divisées en plusieurs types : exécution du JavaScript, mise à jour du layout, et ainsi de suite... Ainsi que l'idée qu'à n'importe quel point donné dans le temps, le navigateur effectue l'une ou l'autre de ces actions.

Donc, si vous voyez un problème de performance - une chute du frame rate par exemple - vous pouvez utiliser la chronologie pour voir ce que le navigateur faisait à ce moment de l'enregistrement.

L'axe X représente le temps. Les opérations enregistrées, appelées marqueurs sont affichées sous la forme de barres de couleur horizontales. Ces marqueurs sont disposés en cascade pour refléter le caractère séquentiel de l'exécution du navigateur.

Lorsqu'un marqueur est sélectionné, des informations supplémentaires sur celui-ci s'affichent dans le panneau de droite. Ces informations intègrent la durée du marqueur et quelques informations spécifiques de son type.

Marqueurs

Les marqueurs possèdent un code couleur et un libellé. Les opérations suivantes sont enregistrées :

Nom et description Couleur Informations détaillées

Évènements DOM

Le code JavaScript qui est exécuté en réponse à un évènement DOM.

Type de l'évènement
Par exemple, "click" ou "message".
Phase de l'évènement
Par exemple "Target" ou "Capture".

Les fonctions JavaScript exécutées dans la page ont le libellé de la raison pour laquelle la fonction a été appelée :

Script Tag
setInterval
setTimeout
requestAnimationFrame
Promise Callback
Promise Init
Worker
JavaScript URI
Event Handler

Pile
La pile d'appels avec des liens vers les fonctions.

Parse HTML

Le temps passé à parser le HTML de la page.

Pile
La pile d'appels avec des liens vers les fonctions.

Parse XML

Le temps passé à parser le XML de la page.

Pile
La pile d'appels avec des liens vers les fonctions.

Recalcul des styles

Le calcul des styles qui s'appliquent aux éléments de la page.

Causes du recalcul
Une chaine de caractères indiquant quel type de recalcul est nécessaire. Elle peut prendre les valeurs suivantes :
Self
Subtree
LaterSiblings
CSSTransitions
CSSAnimations
SVGAttrAnimations
StyleAttribute
StyleAttribute_Animations
Force
ForceDescendants

Layout

Le calcul des positions et de la taille des éléments de la page. Cette opération est parfois appelée "reflow".

Paint

Affichage des pixels à l'écran

Ramasse-miettes

évènement de garbage collection. Les évènements GC non incrémentaux sont nommés "non incrémentiel".

Raison
Une chaine de caractères indiquant la raison pour laquelle le ramasse-miettes a été effectué.
Raison du cycle non incrémentiel
Si l'évènement n'était pas incrémentiel, une chaine expliquant pourquoi la GC a été effectuée.

Nouveau dans Firefox 46: Si l’évènement GC a été causé par une d'allocation, un nouveau lien "Show Allocation Triggers". Cliquer dessus affiche le profil d'allocation menant à cet évènement.

Voir Allocations et Ramasse-miettes pour plus d'informations.

Cycle Collection

Récupération des structures de données C++ qui sont en "reference-count"

Semblable au ramasse-miette, mais pour les objets C++. Voir l'article de blog de Kyle Huey sur le cycle collection.

Type
Toujours "Collect"

Réduction d'arbre de ramasse-miettes

Préparation/préoptimisation pour le Cycle Collection.

Type

Toujours "ForgetSkippable".

Console

La période entre les appels à console.time() et console.timeEnd().

Nom du timer
L'argument passé aux fonctions console.
Pile au début
La pile d'appels à console.time(), avec des liens vers les fonctions.
Pile de fin
(Nouveau dans Firefox 41). La pile d'appels console.timeEnd(). S'il s'agit d'un appel dans un callback de Promise, cela montrera également la "Async stack".

Timestamp

Un appel unique à console.timeStamp().

Label
L'argument passé à timeStamp().

DOMContentLoaded

L'évènement DOMContentLoaded du document

Load

L'évènement load du document.

Évènement dans le thread principal du worker

Affiché lorsque le thread principal envoie un message à un worker, ou reçoit un message d'un worker.

Un parmi :

Sérialisation des données sur le thread principal
Le thread principal sérialise un message pour l'envoyer au worker
Déserialisation des données sur le thread principal
Le thread principal désérialise un message pour l'envoyer au worker

Worker event in worker thread

Affiché lorsque le worker envoie un message à un worker, ou reçoit un message du thread principal.

Un parmi :

Serialisation des données dans le Worker
Le worker sérialise un message pour l'envoyer au thread principal
Déserialisation des données dans le Worker
Le worker désérialise un message pour l'envoyer au thread principal

Les marqueurs et leurs couleurs sont les mêmes dans la chronologie que dans la vue d'ensemble de la chronologie.

Filtrer les marqueurs

Il est possible de contrôler quels marqueurs sont affichés en utilisant le bouton dans la barre d'outils :

Motifs de la chronologie

Le contenu de l´enregistrement dépend énormément des opérations réalisées par le site : Les sites utilisant beaucoup de JavaScript auront un profil à dominance orange, alors que les sites à contenu visuel dynamique auront beaucoup de violet et de vert. Cependant certains motifs communs peuvent vous indiquer de possibles problèmes de performance.

Chronologie de rendu

Le motif suivant est très courant dans la vue de la chronologie :

C'est une visualisation de l´algorithme de base qu'utilise le navigateur pour mettre à jour la page en réponse à un évènement :

  1. JavaScript Function Call: Un évènement quelconque - par exemple un évènement DOM - a pour effet de lancer du JavaScript. Le code change du DOM ou du CSSOM.
  2. Recalculate Style: Si le navigateur pense que des styles calculés de la page ont changé, il les recalcule.
  3. Layout: Puis, le navigateur utilise les styles calculés pour déterminer la position et la géométrie des éléments. Cette opération est étiquetée "layout", mais on l'appelle aussi « reflow ».
  4. Paint: Enfin, le navigateur a besoin de réafficher les éléments à l'écran. Une dernière étape n'est pas représentée dans cette séquence: La page peut être divisée en couches, qui sont affichées indépendamment puis assemblées lors d'un processus appelé "Composition".

Cette séquence doit se terminer en une seule image, puisque l'écran n'est pas mis à jour avant qu'elle soit terminée. Il est communément admis que 60 images/secondes est la vitesse à laquelle les animations apparaîtront fluides. Pour un taux de 60 images/secondes, cela laisse au navigateur 16,7 millisecondes pour exécuter le flow complet.

Il est important pour la réactivité à ce que le navigateur n´ait pas à passer par toutes ces étapes à chaque fois :

L'article Animer des propriétés CSS montre qu'animer différentes propriétés CSS peut donner des résultats de performance différents, et comment la chronologie peut aider à le voir.

JavaScript bloquant

Par défaut, le JavaScript des pages web est exécuté sur le même thread que celui que le navigateur utilise pour les mises à jour de layout, les repaints, les évènements DOM et ainsi de suite. Cela signifie que des fonctions JavaScript qui mettent longtemps à s´exécuter peuvent causer des ralentissements (jank). Les animations ne seront pas fluides et le site pourra même freezer.

En utilisant l'outil frame rate et la « chronologie », il est facile de voir lorsque des fonctions JavaScript posent problème. Dans la capture d´écran ci-dessous, un zoom a été fait sur une fonction JS qui cause une chute du frame rate :

L'article JavaScript Intensif montre comment la « chronologie » peut mettre en évidence les problèmes de réactivité causés par des fonctions JavaScript trop gourmandes, et comment utiliser des méthodes asynchrones pour garder le thread principal réactif.

« Décorations » coûteuses

Certains effets tels que box-shadow, peuvent être coûteux ; surtout lors de transitions où le navigateur doit recalculer cet effet à chaque image. Si vous remarquez des chutes de frame rate surtout lors d'opérations et transitions graphiques couteuses, recherchez les longs marqueurs verts (repaint) dans la chronologie.

Ramasse-miettes (Garbage Collection)

Les marqueurs rouges dans la chronologie représentent le passage du ramasse-miettes (GC), pour lequel SpiderMonkey (le moteur JavaScript de Firefox) parcourt la pile à la recherche d´éléments en mémoire qui ne sont plus accessible pour les libérer. La GC est un indice de performance, car lorsqu’elle « tourne », le moteur JavaScript doit être en pause et donc le programme est mis en pause et ne répondra pas.

Pour aider à réduire la durée de ces pauses, SpiderMonkey implémente une GC morcelée. Cela signifie qu´il peut faire de la garbage collection par petites « passes », permettant au programme de tourner entre celles-ci. Parfois, le moteur à besoin de réaliser une garbage collection complète et non par morceaux et alors, le programme a besoin d'attendre la fin de cette opération.

Pour essayer d’éviter les évènements GC et surtout les passages complets, il est sage de ne pas essayer d'optimiser pour l'implémentation spécifique du moteur JavaScript. SpiderMonkey utilise un ensemble complexe d'heuristiques pour déterminer quand la GC est nécessaire, et quand une GC non incrémentale en particulier est nécessaire. En général cependant :

Lorsque la Chronologie enregistre un marqueur GC, cela indique :

Ajouter des marqueurs avec la console API

Deux marqueurs peuvent être contrôlés par des appels à la console API : "Console" et "Timestamp".

Marqueurs de console

Ces marqueurs permettent de marquer une section spécifique de l'enregistrement.

Pour faire un marqueur console, il faut appeler console.time() au début d'une section, et console.timeEnd() à la fin. Ces fonctions prennent un argument qui est le nom de la section.

Par exemple si nous avons un code comme ceci :

var iterations = 70;
var multiplier = 1000000000;

function calculatePrimes() {

  console.time("calculating...");

  var primes = [];
  for (var i = 0; i < iterations; i++) {
    var candidate = i * (multiplier * Math.random());
    var isPrime = true;
    for (var c = 2; c <= Math.sqrt(candidate); ++c) {
      if (candidate % c === 0) {
          // not prime
          isPrime = false;
          break;
       }
    }
    if (isPrime) {
      primes.push(candidate);
    }
  }

  console.timeEnd("calculating...");

  return primes;
}

La sortie de la Chronologie ressemblera à ceci :

Le marqueur est nommé par l'argument passé à console.time(), et lorsque le marqueur est sélectionné, il est possible de voir la pile du programme dans l'encadré sur le coté droit.

Tache Async

Nouveau dans Firefox 41.

À partir de Firefox 41, l'encadré de droite affichera également la stack à la fin de la période. C´est à dire au moment où console.timeEnd() a été appelé. Si console.timeEnd() a été appelé par la résolution d'une Promise, l'encadré affichera également le label "(Async: Promise)", sous lequel sera affiché la "async stack" : Il s'agit de la pile d'appels au moment où la promise a été faite.

Par exemple, avec ce code :

var timerButton = document.getElementById("timer");
timerButton.addEventListener("click", handleClick, false);

function handleClick() {
  console.time("timer");
  runTimer(1000).then(timerFinished);
}

function timerFinished() {
  console.timeEnd("timer");
  console.log("ready!");
}

function runTimer(t) {
  return new Promise(function(resolve) {
    setTimeout(resolve, t);
  });
}

La Chronologie affichera un marqueur pour la période entre time() et timeEnd(), et s’il est sélectionné, la pile async apparaitra dans l'encadré :

Marqueurs de temps

Les Timestamps permettent de marquer un instant dans l'enregistrement.

Pour faire un timestamp, il faut appeler console.timeStamp(). Il est possible de passer un argument pour nommer le timestamp.

Par exemple, supposons que nous adaptions le code au-dessus pour faire un timestamp toutes les 10 itérations de la boucle ayant pour nom le nombre de l'itération :

var iterations = 70;
var multiplier = 1000000000;

function calculatePrimes() {
  console.time("calculating...");

  var primes = [];
  for (var i = 0; i < iterations; i++) {

    if (i % 10 == 0) {
      console.timeStamp(i.toString());
    }

    var candidate = i * (multiplier * Math.random());
    var isPrime = true;
    for (var c = 2; c <= Math.sqrt(candidate); ++c) {
      if (candidate % c === 0) {
          // not prime
          isPrime = false;
          break;
       }
    }
    if (isPrime) {
      primes.push(candidate);
    }
  }
  console.timeEnd("calculating...");
  return primes;
}

Dans la Chronologie, vous verrez quelque chose comme ceci :