Améliorer les performances de votre application HTML5

Introduction

Le HTML5 nous offre d'excellents outils pour améliorer l'apparence visuelle des applications Web. Cela est particulièrement vrai dans le domaine des animations. Cependant, ce nouveau pouvoir s'accompagne de nouveaux défis. En fait, ces défis ne sont pas vraiment nouveaux et il peut parfois être judicieux de demander à votre sympathique voisin de bureau, le programmeur Flash, comment elle a surmonté des choses similaires par le passé.

Quoi qu'il en soit, lorsque vous travaillez dans des animations, il est extrêmement important que les utilisateurs perçoivent ces animations comme étant fluides. Ce que nous devons comprendre, c'est que la fluidité des animations ne peut pas vraiment être obtenue en augmentant simplement le nombre d'images par seconde au-delà d'un seuil cognitif. Notre cerveau est malheureusement plus intelligent que cela. Vous découvrirez que 30 images par seconde (FPS) réelles sont bien meilleures qu'une fréquence de 60 FPS avec seulement quelques images perdues au milieu. Les gens détestent l'irrégularité.

Cet article a pour but de vous présenter les outils et techniques qui vous permettront d'améliorer l'expérience de votre propre application.

Stratégie

Nous ne souhaitons en aucun cas vous décourager de créer de superbes applications visuellement attrayantes avec HTML5.

Lorsque vous remarquez que les performances peuvent être améliorées, revenez ici et découvrez comment améliorer les éléments de votre application. Bien sûr, elle peut vous aider à bien faire certaines choses dès le départ, mais elle ne vous empêche pas d'être productif.

Fidélité visuelle ++ avec HTML5

Accélération matérielle

L'accélération matérielle représente une étape importante pour les performances globales d'affichage dans le navigateur. Le schéma général consiste à décharger les tâches qui seraient normalement calculées par le processeur principal vers le processeur graphique (GPU) de l'adaptateur graphique de votre ordinateur. Cela peut se traduire par des gains de performances considérables et par une réduction de la consommation de ressources sur les appareils mobiles.

Ces aspects de votre document peuvent être accélérés par le GPU

  • Composition générale de la mise en page
  • Transitions CSS3
  • Transformations 3D CSS3
  • Dessin sur toile
  • Dessin 3D WebGL

Si l'accélération du canevas et de WebGL sont des fonctionnalités spéciales qui peuvent ne pas s'appliquer à votre application spécifique, les trois premiers aspects peuvent aider presque toutes les applications à devenir plus rapides.

Que peut-on accélérer ?

L'accélération GPU consiste à décharger les tâches bien définies et spécifiques sur du matériel spécifique. Le principe est le suivant : votre document est divisé en plusieurs « calques » qui sont invariants par rapport aux aspects de votre page qui sont accélérés. Ces couches sont affichées à l'aide du pipeline de rendu traditionnel. Le GPU est ensuite utilisé pour composer les couches sur une seule page en appliquant des "effets" qui peuvent être accélérés à la volée. Il est possible qu'un objet animé à l'écran ne nécessite pas une seule "remise en page" de la page pendant que l'animation se produit.

Ce que vous devez retenir, c'est que vous devez permettre au moteur de rendu de déterminer facilement quand il peut appliquer la magie de l'accélération GPU. Prenons l'exemple suivant :

Bien que cela fonctionne, le navigateur ne sait pas vraiment que vous effectuez quelque chose qui est censé être perçu comme une animation fluide par un être humain. Réfléchissez à ce qui se passe lorsque vous obtenez la même apparence visuelle en utilisant des transitions CSS3 à la place:

La manière dont le navigateur implémente cette animation n'est pas du tout visible pour le développeur. Cela signifie que le navigateur peut appliquer des astuces telles que l'accélération du GPU pour atteindre l'objectif défini.

Deux indicateurs de ligne de commande utiles permettent de déboguer l'accélération GPU dans Chrome:

  1. --show-composited-layer-borders affiche une bordure rouge autour des éléments manipulés au niveau du GPU. Parfait pour confirmer que vos manipulations ont lieu dans la couche GPU.
  2. --show-paint-rects est appliqué à toutes les modifications non GPU, ce qui génère une bordure claire autour de toutes les zones repeintes. Vous pouvez voir comment le navigateur optimise les zones de peinture.

Safari comporte des indicateurs d'exécution similaires décrits ici.

Transitions CSS3

Les transitions CSS rendent l'animation de style simple pour tout le monde, mais elles constituent également une fonctionnalité intelligente de performance. Étant donné qu'une transition CSS est gérée par le navigateur, la fidélité de son animation peut être considérablement améliorée et, dans de nombreux cas, accélérée du matériel. Actuellement, WebKit (Chrome, Safari, iOS) propose des transformations CSS accélérées par le matériel, mais il sera bientôt disponible sur d'autres navigateurs et plates-formes.

Vous pouvez utiliser des événements transitionEnd pour créer des combinaisons efficaces. Toutefois, pour le moment, pour capturer tous les événements de fin de transition compatibles, vous devez surveiller webkitTransitionEnd transitionend oTransitionEnd.

De nombreuses bibliothèques ont désormais introduit des API d'animation qui exploitent les transitions si elles sont présentes et reviennent à l'animation de style DOM standard dans le cas contraire. scripty2, YUI transition, jQuery animate améliorée.

Traduction CSS3

Je suis sûr que vous avez déjà animé la position x/y d'un élément sur la page. Vous avez probablement manipulé les propriétés gauche et supérieure du style intégré. Avec les transformations 2D, nous pouvons utiliser la fonctionnalité translate() pour reproduire ce comportement.

Nous pouvons combiner cela avec l'animation DOM pour utiliser la meilleure solution possible.

<div style="position:relative; height:120px;" class="hwaccel">

  <div style="padding:5px; width:100px; height:100px; background:papayaWhip;
              position:absolute;" id="box">
  </div>
</div>

<script>
document.querySelector('#box').addEventListener('click', moveIt, false);

function moveIt(evt) {
  var elem = evt.target;

  if (Modernizr.csstransforms && Modernizr.csstransitions) {
    // vendor prefixes omitted here for brevity
    elem.style.transition = 'all 3s ease-out';
    elem.style.transform = 'translateX(600px)';

  } else {
    // if an older browser, fall back to jQuery animate
    jQuery(elem).animate({ 'left': '600px'}, 3000);
  }
}
</script>

Nous utilisons Modernizr pour tester les fonctionnalités des transformations CSS 2D et des transitions CSS. Si c'est le cas, nous allons utiliser la fonction de translation pour modifier la position. Si elle est animée à l'aide d'une transition, il y a de fortes chances que le navigateur puisse l'accélérer. Pour pousser le navigateur à nouveau dans la bonne direction, nous allons utiliser la formule "magic CSS bullet" ci-dessus.

Si ce n'est pas le cas, nous utiliserons jQuery pour déplacer notre élément. Pour que tout cela soit automatique, vous pouvez utiliser le plug-in jQuery Transform polyfill de Louis-Remi Babe.

window.requestAnimationFrame

requestAnimationFrame a été introduit par Mozilla et itéré par WebKit dans le but de vous fournir une API native pour exécuter des animations, qu'elles soient basées sur DOM/CSS, ou sur <canvas> ou WebGL. Le navigateur peut optimiser les animations simultanées en un seul cycle de reflow et de repeinture, ce qui permet d'obtenir une animation plus fidèle. Par exemple, les animations JS synchronisées avec des transitions CSS ou des fichiers SMIL SVG. De plus, si vous lancez la lecture en boucle de l'animation dans un onglet qui n'est pas visible, le navigateur ne la poursuit pas, ce qui réduit l'utilisation du processeur, du GPU et de la mémoire, ce qui augmente l'autonomie de la batterie.

Pour savoir comment et pourquoi utiliser requestAnimationFrame, consultez l'article de Paul Irish (requestAnimationFrame for smart animating).

Profilage

Une fois que vous avez découvert que la vitesse de votre application peut être améliorée, il est temps d'approfondir le profilage afin de déterminer où les optimisations pourraient être les plus utiles. Les optimisations ont souvent un impact négatif sur la gestion de votre code source et ne doivent donc être appliquées que si cela est nécessaire. Le profilage vous permet d'identifier les parties de votre code qui bénéficieraient le plus d'une amélioration des performances.

Profilage JavaScript

Les profileurs JavaScript vous offrent un aperçu des performances de votre application au niveau de la fonction JavaScript en mesurant le temps nécessaire pour exécuter chaque fonction du début à la fin.

Le temps d'exécution brut d'une fonction correspond au temps total nécessaire pour l'exécuter de haut en bas. Le temps d'exécution net correspond au temps d'exécution brut moins le temps nécessaire pour exécuter les fonctions appelées à partir de la fonction.

Certaines fonctions sont appelées plus souvent que d'autres. Les profileurs vous donnent généralement le temps nécessaire à l'exécution de tous les appels, ainsi que la durée d'exécution moyenne, minimale et maximale.

Pour en savoir plus, consultez la documentation des outils pour les développeurs Chrome sur le profilage.

Le DOM

Les performances de JavaScript ont une grande influence sur la fluidité et la réactivité de votre application. Il est important de comprendre que si les profileurs JavaScript mesurent le temps d'exécution de votre code JavaScript, ils mesurent également indirectement le temps consacré aux opérations DOM. Ces opérations DOM sont souvent au cœur des problèmes de performances.

function drawArray(array) {
  for(var i = 0; i < array.length; i++) {
    document.getElementById('test').innerHTML += array[i]; // No good :(
  }
}

Par exemple, dans le code ci-dessus, presque aucun temps n'est consacré à l'exécution du code JavaScript réel. Il est toujours très probable que la fonction drawArray apparaisse dans vos profils, car elle interagit avec le DOM de manière très inefficace.

Conseils et astuces

Fonctions anonymes

Les fonctions anonymes ne sont pas faciles à profiler car elles n'ont pas de nom sous lequel elles pourraient apparaître dans le profileur. Il existe deux façons de contourner ce problème :

$('.stuff').each(function() { ... });

réécrire en:

$('.stuff').each(function workOnStuff() { ... });

Il n'est pas courant que JavaScript soit compatible avec l'attribution de noms aux expressions de fonction. Elles s'afficheront ainsi parfaitement dans le profileur. Cette solution présente un problème: l'expression nommée place en fait le nom de la fonction dans le champ d'application lexical actuel. Cela risque de perturber les autres symboles, alors faites attention.

Profiler des fonctions longues

Imaginez que vous avez une fonction longue et que vous pensez qu'une petite partie de celle-ci pourrait être la cause de vos problèmes de performances. Il existe deux façons d'identifier l'origine du problème:

  1. La bonne méthode: refactorisez votre code pour n'inclure aucune fonction longue.
  2. Méthode maléfique: ajoutez des instructions sous la forme de fonctions d'auto-appel nommées à votre code. Si vous faites attention, cela ne modifie pas la sémantique et fait apparaître certaines parties de votre fonction en tant que fonctions individuelles dans le profileur : js function myLongFunction() { ... (function doAPartOfTheWork() { ... })(); ... } N'oubliez pas de supprimer ces fonctions supplémentaires une fois le profilage terminé. Vous pouvez même les utiliser comme point de départ pour refactoriser votre code.

Profilage DOM

Les derniers outils de développement de Chrome Web Inspector contiennent la nouvelle "vue chronologique", qui montre une chronologie des actions de niveau inférieur effectuées par le navigateur. Vous pouvez utiliser ces informations pour optimiser vos opérations DOM. Vous devez essayer de réduire le nombre d'actions que le navigateur doit effectuer pendant l'exécution de votre code.

La vue chronologique peut générer une immense quantité d'informations. Vous devez donc essayer de créer des scénarios de test minimaux que vous pouvez exécuter indépendamment.

Profilage DOM

L'image ci-dessus montre la sortie de la vue chronologique pour un script très simple. Le volet de gauche affiche les opérations effectuées par le navigateur dans l'ordre chronologique, tandis que la chronologie du volet de droite affiche le temps réel consommé par une opération individuelle.

En savoir plus sur la vue chronologique DynaTrace Ajax Edition est un autre outil de profilage dans Internet Explorer.

Stratégies de profilage

Identifier des aspects

Lorsque vous voulez profiler votre application, essayez d'identifier le plus près possible des aspects de sa fonctionnalité susceptibles de provoquer une lenteur. Essayez ensuite d'exécuter une exécution de profil qui n'exécute que les parties de votre code qui sont pertinentes pour ces aspects de votre application. Les données de profilage seront ainsi plus faciles à interpréter, car elles ne sont pas mélangées avec des chemins de code qui ne sont pas liés à votre problème réel. Voici quelques exemples illustrant des aspects spécifiques de votre application:

  1. Temps de démarrage (activer le profileur, recharger l'application, attendre la fin de l'initialisation, arrêter le profileur).
  2. Cliquez sur un bouton et l'animation qui en découle (démarrer le profileur, cliquer sur le bouton, attendre la fin de l'animation, arrêter le profileur).
Profilage d'IUG

Exécuter uniquement la partie droite de votre application peut s'avérer plus difficile dans un programme IUG que lorsque vous optimisez, par exemple, le ray tracer de votre moteur 3D. Par exemple, lorsque vous souhaitez profiler les événements qui se produisent lorsque vous cliquez sur un bouton, vous risquez de déclencher des événements de survol avec la souris non pertinents, ce qui rend vos résultats moins concluants. Évitez cela :)

Interface de programmation

Une interface de programmation permet également d'activer le débogueur. Cela permet de contrôler précisément quand le profilage commence et se termine.

Démarrez un profilage avec la commande suivante:

console.profile()

Arrêtez le profilage avec la commande suivante:

console.profileEnd()

Reproductibilité

Lors du profilage, assurez-vous de pouvoir reproduire vos résultats. Ce n'est qu'alors que vous pourrez déterminer si vos optimisations ont réellement permis d'améliorer les choses. Le profilage au niveau de la fonction s'effectue également dans le contexte de l'ensemble de votre ordinateur. Ce n'est pas une science exacte. Les exécutions de profil individuelles peuvent être influencées par de nombreux autres éléments qui se produisent sur votre ordinateur:

  1. Minuteur non lié à votre propre application, qui se déclenche pendant que vous mesurez autre chose.
  2. Le récupérateur de mémoire en cours d'exécution.
  3. Un autre onglet de votre navigateur effectuant des tâches fastidieuses dans le même thread d'exploitation.
  4. Un autre programme de votre ordinateur utilise le processeur, ce qui ralentit votre application.
  5. Changements soudains du champ gravitationnel de la Terre.

Il est également judicieux d'exécuter le même chemin de code plusieurs fois au cours d'une même session de profilage. Vous réduisez ainsi l'influence des facteurs ci-dessus, et les parties lentes peuvent se démarquer encore plus clairement.

Mesurer, améliorer, mesurer

Lorsque vous avez identifié un point lent de votre programme, essayez de trouver des moyens d'améliorer le comportement d'exécution. Une fois le code modifié, effectuez un nouveau profilage. Si vous êtes satisfait du résultat, passez à autre chose. Si vous ne constatez aucune amélioration, vous devriez probablement effectuer un rollback de votre modification et ne pas la laisser dans "car cela ne peut pas nuire".

Stratégies d'optimisation

Réduire les interactions DOM

Pour améliorer la vitesse des applications clientes Web, il est courant de vouloir minimiser les interactions DOM. Si la vitesse des moteurs JavaScript a augmenté dans un certain ordre de grandeur, l'accès au DOM n'a pas été aussi rapide. C'est aussi pour des raisons très pratiques qui n'arrivent jamais (la mise en page et le dessin sur un écran prennent du temps, par exemple).

Mettre en cache les nœuds DOM

Chaque fois que vous récupérez un nœud ou une liste de nœuds à partir du DOM, demandez-vous si vous pouvez les réutiliser dans un calcul ultérieur (ou même simplement lors de l'itération de boucle suivante). C'est souvent le cas tant que vous n'ajoutez ou ne supprimez pas de nœuds dans la zone concernée.

Avant :

function getElements() {
  return $('.my-class');
}

Après :

var cachedElements;
function getElements() {
  if (cachedElements) {
    return cachedElements;
  }
  cachedElements = $('.my-class');
  return cachedElements;
}

Mettre en cache les valeurs d'attribut

De la même manière que vous mettez en cache les nœuds DOM, vous pouvez mettre en cache les valeurs des attributs. Imaginons que vous animez un attribut du style d'un nœud. Si vous savez que vous (comme dans cette partie du code) êtes le seul à pouvoir toucher cet attribut, vous pouvez mettre en cache la dernière valeur à chaque itération, afin de ne pas avoir à la lire plusieurs fois.

Avant :

setInterval(function() {
  var ele = $('#element');
  var left = parseInt(ele.css('left'), 10);
  ele.css('left', (left + 5) + 'px');
}, 1000 / 30);

Après : js var ele = $('#element'); var left = parseInt(ele.css('left'), 10); setInterval(function() { left += 5; ele.css('left', left + 'px'); }, 1000 / 30);

Déplacer la manipulation DOM hors des boucles

Les boucles sont souvent des points chauds d'optimisation. Essayez de trouver des moyens de dissocier le traitement des nombres réels pour travailler avec le DOM. Il est souvent possible d'effectuer un calcul, puis d'appliquer ensuite tous les résultats en une seule fois.

Avant :

document.getElementById('target').innerHTML = '';
for(var i = 0; i < array.length; i++) {
  var val = doSomething(array[i]);
  document.getElementById('target').innerHTML += val;
}

Après :

var stringBuilder = [];
for(var i = 0; i < array.length; i++) {
  var val = doSomething(array[i]);
  stringBuilder.push(val);
}
document.getElementById('target').innerHTML = stringBuilder.join('');

Redessinations et ajustement de la mise en page

Comme indiqué précédemment, l'accès au DOM est relativement lent. Cela devient très lent lorsque votre code lit une valeur qui doit être recalculée, car votre code a récemment modifié un élément lié dans le DOM. Par conséquent, il est préférable d'éviter de mélanger les accès en lecture et en écriture au DOM. Idéalement, votre code doit toujours être regroupé en deux phases:

  • Phase 1: Lire les valeurs DOM nécessaires pour votre code
  • Phase 2: Modifier le DOM

Essayez de ne pas programmer un modèle tel que:

  • Phase 1: Lire les valeurs DOM
  • Phase 2: Modifier le DOM
  • Phase 3: En savoir plus
  • Phase 4: modifiez le DOM à un autre endroit.

Avant :

function paintSlow() {
  var left1 = $('#thing1').css('left');
  $('#otherThing1').css('left', left);
  var left2 = $('#thing2').css('left');
  $('#otherThing2').css('left', left);
}

Après :

function paintFast() {
  var left1 = $('#thing1').css('left');
  var left2 = $('#thing2').css('left');
  $('#otherThing1').css('left', left);
  $('#otherThing2').css('left', left);
}

Ce conseil doit être pris en compte pour les actions qui se produisent dans un contexte d'exécution JavaScript. (par exemple, dans un gestionnaire d'événements, dans un gestionnaire d'intervalles ou lors du traitement d'une réponse Ajax).

L'exécution de la fonction paintSlow() ci-dessus crée l'image suivante:

paintSlow()

Si vous passez à l'implémentation la plus rapide, vous obtenez l'image suivante:

Implémentation plus rapide

Ces images montrent que réorganiser la façon dont votre code accède au DOM peut améliorer considérablement les performances d'affichage. Dans ce cas, le code d'origine doit recalculer les styles et mettre en page deux fois la page pour créer le même résultat. Une optimisation similaire peut être appliquée à l'ensemble du code du "monde réel" et produire des résultats vraiment spectaculaires.

En savoir plus: Rendu: repaint, reflow/relayout, restyle de Stoyan Stefanov

Redessinages et boucle d'événements

L'exécution de JavaScript dans le navigateur suit un modèle de "boucle d'événements". Par défaut, le navigateur est inactif. Cet état peut être interrompu par des événements issus d'interactions utilisateur, tels que des minuteurs JavaScript ou des rappels Ajax. Lorsqu'un élément JavaScript s'exécute à un tel point d'interruption, le navigateur attend généralement qu'il se termine jusqu'à ce qu'il repeigne l'écran (il peut y avoir des exceptions pour les scripts JavaScript de très longue durée ou dans des cas tels que des boîtes d'alerte qui interrompent efficacement l'exécution de JavaScript).

Conséquences

  1. Si l'exécution de vos cycles d'animation JavaScript prend plus de 1/30 seconde, vous ne pourrez pas créer d'animations fluides, car le navigateur ne repeindra pas pendant l'exécution JS. Lorsque vous prévoyez de gérer également les événements utilisateur, vous devez être beaucoup plus rapide.
  2. Il est parfois utile de reporter certaines actions JavaScript à quelques instants. Exemple : setTimeout(function() { ... }, 0) Cela indique au navigateur d'exécuter le rappel dès que la boucle d'événements est à nouveau inactive (en réalité, certains navigateurs attendent au moins 10 ms). Vous devez savoir que cela va créer deux cycles d'exécution JavaScript très proches dans le temps. Les deux peuvent déclencher un repeindre de l'écran, ce qui peut doubler le temps total consacré à la peinture. Le déclenchement de deux peintures dépend de la méthode heuristique utilisée dans le navigateur.

Version standard:

function paintFast() {
  var height1 = $('#thing1').css('height');
  var height2 = $('#thing2').css('height');
  $('#otherThing1').css('height', '20px');
  $('#otherThing2').css('height', '20px');
}
Redessinages et boucle d&#39;événements

Ajoutons un délai:

function paintALittleLater() {
  var height1 = $('#thing1').css('height');
  var height2 = $('#thing2').css('height');
  $('#otherThing1').css('height', '20px');
  setTimeout(function() {
    $('#otherThing2').css('height', '20px');
  }, 10)
}
Delay (Délai)

La version différée montre que le navigateur affiche deux fois alors que les deux modifications apportées à la page ne représentent que 1/100 de seconde.

Initialisation différée

Les utilisateurs sont à la recherche d'applications Web qui se chargent rapidement et sont réactives. Cependant, les seuils de ce qu'ils perçoivent comme lents varient en fonction de l'action qu'ils effectuent. Par exemple, une application ne doit jamais effectuer beaucoup de calculs lors d'un événement de survol avec la souris, car cela pourrait nuire à l'expérience utilisateur pendant que l'utilisateur continue à déplacer sa souris. Cependant, les utilisateurs ont l'habitude d'accepter un petit délai après avoir cliqué sur un bouton.

Il peut donc être judicieux de déplacer votre code d'initialisation pour qu'il s'exécute le plus tard possible (par exemple, lorsque l'utilisateur clique sur un bouton qui active un composant particulier de votre application).

Avant : js var things = $('.ele > .other * div.className'); $('#button').click(function() { things.show() });

Après : js $('#button').click(function() { $('.ele > .other * div.className').show() });

Délégation d'événement

Répartir les gestionnaires d'événements sur une page peut prendre un temps relativement long. Cette opération peut également s'avérer fastidieuse une fois que les éléments sont remplacés de manière dynamique, ce qui nécessite de rattacher les gestionnaires d'événements aux nouveaux éléments.

Dans ce cas, la solution consiste à utiliser une technique appelée délégation d'événement. Au lieu d'associer des gestionnaires d'événements individuels aux éléments, la nature ébullatoire de nombreux événements de navigateur est utilisée en associant le gestionnaire d'événements à un nœud parent et en vérifiant le nœud cible de l'événement pour voir si l'événement présente un intérêt.

En jQuery, cela peut facilement être exprimé comme suit:

$('#parentNode').delegate('.button', 'click', function() { ... });

Dans quels cas ne pas utiliser la délégation d'événement ?

Parfois, l'inverse peut se produire: vous utilisez la délégation d'événements et vous rencontrez un problème de performances. Fondamentalement, la délégation d'événements permet un temps d'initialisation de complexité constante. Toutefois, le prix de la vérification d'un événement intéressant doit être payé pour chaque appel de cet événement. Cela peut être coûteux, en particulier pour les événements qui se produisent fréquemment, comme "mouseover" ou même "mousemove".

Problèmes typiques et solutions

Les actions que je fais dans $(document).ready prennent beaucoup de temps

Conseil personnel de Malte: ne faites jamais rien en $(document).ready. Essayez de remettre votre document dans sa forme finale. D'accord, vous êtes autorisé à enregistrer des écouteurs d'événements, mais uniquement à l'aide du sélecteur d'ID et/ou de la délégation d'événements. Pour les événements coûteux tels que "mousemove", retardez l'enregistrement jusqu'à ce qu'ils soient nécessaires (événement "mouseover" sur l'élément concerné).

Et si vous avez vraiment besoin de faire des choses, comme faire une demande Ajax pour obtenir des données réelles, diffusez une belle animation ; vous pouvez inclure l'animation en tant qu'URI de données s'il s'agit d'un GIF animé ou autre.

Depuis que j'ai ajouté un fichier animé Flash sur la page, tout est très lent

L'ajout d'éléments Flash à une page ralentit toujours légèrement l'affichage, car la mise en page finale de la fenêtre doit être "négociée" entre le navigateur et le plug-in Flash. Si vous ne pouvez pas complètement éviter d'insérer du contenu Flash dans vos pages, assurez-vous de définir le paramètre Flash "wmode" sur la valeur "window" (valeur par défaut). Cette opération désactive la combinaison d'éléments HTML et Flash (l'élément HTML situé au-dessus de l'animation Flash et votre animation Flash ne peuvent pas être transparents). Cela peut être un inconvénient, mais cela améliorera considérablement vos performances. Découvrez par exemple comment youtube.com évite de placer des calques au-dessus du lecteur de films principal.

J'enregistre des éléments dans localStorage, maintenant mon application est saccadée

L'écriture sur localStorage est une opération synchrone qui implique le démarrage de votre disque dur. Il est préférable de ne jamais effectuer d'opérations synchrones de longue durée lorsque vous réalisez des animations. Déplacez l'accès à localStorage vers un endroit de votre code, où vous êtes sûr que l'utilisateur est inactif et qu'aucune animation n'est en cours.

Le profilage indique que le sélecteur jQuery est très lent

Vous devez d'abord vous assurer que votre sélecteur peut être exécuté via document.querySelectorAll. Vous pouvez tester cela dans la console JavaScript. S'il existe une exception, réécrivez votre sélecteur pour ne pas utiliser d'extension spéciale de votre framework JavaScript. Ainsi, votre sélecteur sera beaucoup plus rapide dans les navigateurs récents.

Si le problème persiste ou si vous souhaitez également bénéficier de la rapidité dans les navigateurs récents, suivez ces consignes:

  • Soyez aussi précis que possible à droite du sélecteur.
  • Indiquez un nom de tag que vous n'utilisez pas souvent pour placer le sélecteur tout à droite.
  • Si rien ne vous aide, réécrivez le code pour pouvoir utiliser un sélecteur d'ID.

Toutes ces manipulations DOM prennent du temps

De nombreuses insertions, suppressions et mises à jour de nœuds DOM peuvent être très lentes. Pour une optimisation, vous pouvez généralement générer une grande chaîne HTML et utiliser domNode.innerHTML = newHTML pour remplacer l'ancien contenu. Notez que cela peut nuire à la gestion et créer des liens mémoire dans IE, soyez donc prudent.

Un autre problème courant est que le code d'initialisation peut générer beaucoup de code HTML. Par exemple, un plug-in jQuery qui transforme une zone de sélection en plusieurs éléments div, car c'est ce que les concepteurs voulaient, sans tenir compte des bonnes pratiques en matière d'expérience utilisateur. Si vous voulez vraiment que votre page soit rapide, ne le faites jamais. À la place, envoyez tout le balisage côté serveur dans sa forme finale. Cela pose encore de nombreux problèmes, alors demandez-vous bien si la vitesse en vaut la peine.

Outils

  1. JSPerf : effectuer une analyse comparative de petits extraits de JavaScript
  2. Firebug : Pour le profilage dans Firefox
  3. Outils pour les développeurs Google Chrome (disponibles en tant qu'inspecteur Web dans Safari)
  4. DOM Monster : pour optimiser les performances DOM
  5. DynaTrace Ajax Edition : pour le profilage et l'optimisation des couleurs dans Internet Explorer

Complément d'informations

  1. Vitesse de Google
  2. Paul Irish sur jQuery Performance
  3. Performances extrêmes avec JavaScript (diapositive)