Javascript Performance Measurement

Mesurer le temps nécessaire à l'exécution d'une fonction est un bon moyen de prouver qu'une implémentation d'un mécanisme est plus productive qu'une autre. Cela vous permet de vous assurer que les performances de la fonction n'ont pas souffert après certaines modifications apportées au code. Il permet également de rechercher les goulots d'étranglement des performances des applications.

Si un projet Web a des performances élevées, cela contribue à sa perception positive par les utilisateurs. Et si les utilisateurs ont aimé travailler avec la ressource, ils ont la propriété de revenir. Par exemple, dans ceL'étude a montré que 88% des clients en ligne sont moins susceptibles de revenir aux ressources qu'ils rencontrent en cas d'inconvénient. Ces inconvénients peuvent être causés par des problèmes de performances.

C'est pourquoi les outils pour aider à trouver les goulots d'étranglement des performances et mesurer les résultats des améliorations apportées au code sont importants dans le développement Web. Ces outils sont particulièrement pertinents dans le développement JavaScript. Il est important de savoir que chaque ligne de code JavaScript peut potentiellement bloquer le DOM, car JavaScript est un langage à thread unique. Dans cet article, je parlerai de la façon de mesurer les performances des fonctions et de ce qu'il faut faire avec les résultats de mesure.





Si vous pensez que certains calculs sont trop lourds à effectuer dans le thread principal, vous pouvez alors décider de les déplacer vers un technicien de service ou un travailleur Web.

Méthode Performance.now ()


L'interface Performance donne accès à une valeur de type DOMHighResTimeStamp via une méthode performance.now(). Cette méthode renvoie un horodatage indiquant le temps en millisecondes qui s'est écoulé depuis que le document a commencé à exister. De plus, la précision de cet indicateur est d'environ 5 microsecondes (fractions de milliseconde).

Afin de mesurer les performances d'un fragment de code à l'aide de la méthode performance.now(), vous devez effectuer deux mesures de temps, enregistrer les résultats de ces mesures dans des variables, puis soustraire les résultats de la première des résultats de la deuxième mesure:

const t0 = performance.now();
for (let i = 0; i < array.length; i++) 
{
  // - 
}
const t1 = performance.now();
console.log(t1 - t0, 'milliseconds');

Dans Chrome, après avoir exécuté ce code, vous pouvez obtenir quelque chose comme ceci:

0.6350000001020817 "milliseconds"

Dans Firefox, comme ceci:

1 milliseconds

Comme vous pouvez le voir, les résultats de mesure obtenus dans différents navigateurs sont très différents. Le fait est que dans Firefox 60, la précision des résultats renvoyés par l'API Performance est réduite. Nous en parlerons davantage.

L'interface Performance a bien plus de capacités que de simplement renvoyer un certain horodatage. Ceux - ci comprennent la mesure de différents aspects de la performance représentée par ces extensions de cette interface comme la Timeline Performance API , Navigation Timing , Timing utilisateur , synchronisation des ressources . Voici le matériel pour en savoir plus sur ces API.

Dans notre cas, nous parlons de mesurer la performance des fonctions, nous avons donc suffisamment d'opportunités que la méthode donneperformance.now().

Date.now () et performance.now ()


Ici, vous pouvez penser que vous pouvez utiliser la méthode pour mesurer les performances Date.now(). C'est en effet possible, mais cette approche présente des inconvénients.

La méthode Date.now()renvoie le temps en millisecondes qui s'est écoulé depuis l'ère Unix (1970-01-01T00: 00: 00Z) et dépend de l'horloge système. Cela signifie non seulement que cette méthode n'est pas aussi précise que performance.now(), mais qu'elle performance.now()renvoie en revanche des valeurs qui, dans certaines conditions, peuvent être basées sur des indicateurs d'horloge incorrects. Voici ce que Rich Gentlekor, un programmeur lié au moteur WebKit, dit: «Peut-être que les programmeurs sont moins susceptibles de penser que les lectures retournées lors de l'accèsDateen fonction de l'heure du système, il est absolument impossible d'appeler idéal pour surveiller des applications réelles. La plupart des systèmes ont un démon qui synchronise régulièrement l'heure. L'ajustement de l'horloge système pendant quelques millisecondes toutes les 15-20 minutes est une chose courante. Avec une telle fréquence, des réglages d'horloge d'environ 1% des intervalles de 10 secondes seront inexacts. »

Méthode Console.time ()


La mesure du temps à l'aide de cette API est extrêmement simple. Assez, avant le code dont vous devez évaluer les performances, appelez la méthode console.time()et après ce code - la méthode console.timeEnd(). Dans ce cas, l'une et les autres méthodes doivent passer le même argument de chaîne. Sur une seule page, jusqu'à 10 000 de ces minuteries peuvent être utilisées simultanément.

La précision des mesures de temps effectuées à l'aide de cette API est la même que lors de l'utilisation de l'API Performance, mais la précision qui sera atteinte dans chaque situation spécifique dépend du navigateur.

console.time('test');
for (let i = 0; i < array.length; i++) {
  // - 
}
console.timeEnd('test');

Après avoir exécuté ce code, le système affichera automatiquement des informations sur le temps écoulé sur la console.

Dans Chrome, cela ressemblera à ceci:

test: 0.766845703125ms

Dans Firefox, comme ceci:

test: 2ms - timer ended

En fait, tout ici est très similaire à ce que nous avons vu en travaillant performance.now().

La force de la méthode console.time()est sa facilité d'utilisation. À savoir, nous parlons du fait que son application ne nécessite pas la déclaration de variables auxiliaires et de trouver la différence entre les indicateurs qui y sont enregistrés.

Précision de temps réduite


Si vous, à l'aide des outils décrits ci-dessus, avez mesuré les performances de votre code dans différents navigateurs, vous pouvez alors prêter attention au fait que les résultats de mesure peuvent varier.

La raison en est que les navigateurs essaient de protéger les utilisateurs contre les attaques temporelles et contre les mécanismes d'identification des navigateurs ( empreinte digitale du navigateur ). Si les résultats de la mesure du temps s'avèrent trop précis, cela peut donner aux attaquants la possibilité, par exemple, d'identifier les utilisateurs.

Dans Firefox 60, comme déjà mentionné, la précision des résultats de mesure du temps est réduite . Pour cela, définissez la privacy.reduceTimerPrecisionvaleur de la propriété sur 2 ms.

Quelque chose à garder à l'esprit lors des tests de performances


Vous disposez désormais d'outils pour mesurer les performances des fonctions JavaScript. Mais avant de vous lancer dans les affaires, vous devez considérer certaines des fonctionnalités dont nous allons parler maintenant.

▍ Diviser pour mieux régner


Supposons qu'en filtrant certaines données, vous fassiez attention au lent fonctionnement de l'application. Mais vous ne savez pas exactement où se situe le goulot d'étranglement des performances.

Au lieu de spéculer sur quelle partie du code est lente, il serait préférable de découvrir en utilisant les méthodes ci-dessus.

Afin de voir l'image générale de ce qui se passe, vous devez d'abord utiliser console.time()et console.timeEnd()évaluer les performances d'un bloc de code, ce qui, vraisemblablement, a un mauvais effet sur les performances. Ensuite, vous devez regarder la vitesse des différentes parties de ce bloc. Si l'un d'eux semble nettement plus lent que les autres, vous devez y porter une attention particulière et savoir comment l'analyser.

Moins il y a de code entre les appels à des méthodes qui mesurent le temps, plus la probabilité que quelque chose qui n'est pas pertinent à la situation problématique soit mesurée est faible.

▍Tenez compte du comportement des fonctions avec différentes valeurs d'entrée


Dans les applications réelles, les données reçues à l'entrée d'une fonction particulière peuvent être très différentes. Si vous mesurez les performances d'une fonction à laquelle un ensemble de données sélectionné au hasard a été transmis, cela ne fournira aucune information précieuse pouvant clarifier ce qui se passe.

Les fonctions lors de la recherche de performances doivent être appelées avec des données d'entrée qui ressemblent autant que possible aux vraies.

▍ Exécuter plusieurs fois les fonctions


Supposons que vous ayez une fonction qui itère sur un tableau. Elle effectue certains calculs en utilisant chaque élément du tableau, puis retourne un nouveau tableau avec les résultats des calculs. En pensant à l'optimisation de cette fonction, vous voulez savoir ce qui fonctionne plus rapidement dans votre situation - une boucle forEachou une boucle régulière for.

Voici deux options pour cette fonctionnalité:

function testForEach(x) {
  console.time('test-forEach');
  const res = [];
  x.forEach((value, index) => {
    res.push(value / 1.2 * 0.1);
  });

  console.timeEnd('test-forEach')
  return res;
}

function testFor(x) {
  console.time('test-for');
  const res = [];
  for (let i = 0; i < x.length; i ++) {
    res.push(x[i] / 1.2 * 0.1);
  }

  console.timeEnd('test-for')
  return res;
}

Testez les fonctions:

const x = new Array(100000).fill(Math.random());
testForEach(x);
testFor(x);

Après avoir exécuté le code, nous obtenons les résultats suivants:

test-forEach: 27ms - timer ended
test-for: 3ms - timer ended

Le cycle semblait forEachêtre beaucoup plus lent que le cycle for. Après tout, les résultats des tests indiquent exactement cela?

En fait, après un seul test, il est trop tôt pour tirer de telles conclusions. Essayons d'appeler les fonctions deux fois:

testForEach(x);
testForEach(x);
testFor(x);
testFor(x);

Nous obtenons ce qui suit:

test-forEach: 13ms - timer ended
test-forEach: 2ms - timer ended
test-for: 1ms - timer ended
test-for: 3ms - timer ended

Il s'avère que la fonction dans laquelle elle est utilisée forEach, appelée la deuxième fois, est aussi rapide que celle dans laquelle elle est utilisée for. Mais, étant donné que la première forEachfonction appelle, la fonction fonctionne beaucoup plus lentement, cela ne vaut peut-être pas la peine de l'utiliser.

▍Tester les performances dans différents navigateurs


Les tests ci-dessus ont été effectués dans Firefox. Mais que faire si vous les exécutez dans Chrome? Les résultats seront complètement différents:

test-forEach: 6.156005859375ms
test-forEach: 8.01416015625ms
test-for: 4.371337890625ms
test-for: 4.31298828125ms

Le fait est que les navigateurs Chrome et Firefox sont basés sur différents moteurs JavaScript qui implémentent différentes optimisations de performances. Il est très utile de connaître ces différences.

Dans ce cas, Firefox a une meilleure optimisation forEachavec une entrée similaire. Et le cycle forest plus rapide que forEachdans Chrome et Firefox. Par conséquent, il vaut probablement mieux s'attarder sur la variante de la fonction c for.

Il s'agit d'un bon exemple, démontrant l'importance de mesurer les performances dans différents navigateurs. Si vous évaluez les performances de certains codes uniquement dans Chrome, vous pouvez conclure que le cycle forEach, par rapport au cycle for, n'est pas si mauvais.

▍ Appliquer des limites artificielles aux ressources système


Les valeurs obtenues dans nos expériences ne semblent pas particulièrement grandes. Mais sachez que les ordinateurs utilisés pour le développement sont généralement beaucoup plus rapides que, par exemple, le téléphone mobile moyen qu'ils utilisent pour naviguer sur le Web.

Afin de vous mettre à la place d'un utilisateur qui ne possède pas l'appareil le plus rapide, utilisez les capacités du navigateur pour limiter artificiellement les ressources système. Par exemple - pour réduire les performances du processeur.

Avec cette approche, 10 ou 50 millisecondes peuvent facilement se transformer en 500.

▍ Mesurer les performances relatives


Les mesures de performances dépendent généralement non seulement du matériel, mais également de la charge actuelle du processeur et de la charge de travail du thread principal de l'application JavaScript. Par conséquent, essayez de vous baser sur des indicateurs relatifs caractérisant le changement de performances, car les indicateurs absolus obtenus lors de l'analyse du même fragment de code à différents moments peuvent varier considérablement.

Sommaire


Dans cet article, nous avons examiné certaines API JavaScript conçues pour mesurer les performances. Nous avons expliqué comment les utiliser pour analyser du code réel. Je crois que pour effectuer des mesures simples, il est plus facile à utiliser console.time().

J'ai le sentiment que de nombreux développeurs front-end ne prêtent pas assez d'attention à la mesure des performances de leurs projets. Et ils doivent surveiller en permanence les indicateurs pertinents, car la productivité affecte la réussite et la rentabilité des projets.

Chers lecteurs! Si vous surveillez constamment la performance de vos projets, veuillez nous dire comment vous le faites.


All Articles