Améliorer les performances de votre application HTML5

Introduction

HTML5 nous fournit d'excellents outils pour améliorer l'apparence visuelle des applications Web. C'est particulièrement vrai dans le domaine des animations. Cependant, ce nouveau pouvoir s'accompagne de nouveaux défis. En réalité, ces défis ne sont pas vraiment nouveaux. Il peut donc être judicieux de demander à votre voisin de bureau, le programmeur Flash, comment il a surmonté des problèmes similaires par le passé.

Quoi qu'il en soit, lorsque vous travaillez sur des animations, il est extrêmement important que les utilisateurs les perçoivent comme fluides. Il faut comprendre que la fluidité des animations ne peut pas être obtenue simplement en augmentant le nombre de frames par seconde au-delà de tout seuil cognitif. Malheureusement, notre cerveau est plus intelligent que cela. Vous apprendrez que 30 images d'animation par seconde (fps) est bien meilleur que 60 fps avec seulement quelques images perdues au milieu. Les utilisateurs détestent les bords dentelés.

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

Stratégie

Nous ne voulons pas vous décourager de créer des applications visuelles incroyables avec HTML5.

Lorsque vous remarquerez que les performances pourraient être un peu meilleures, revenez sur cette page et découvrez comment améliorer les éléments de votre application. Bien sûr, il peut être utile de faire certaines choses correctement dès le départ, mais ne laissez jamais cela vous empêcher d'être productif.

Fidélité visuelle++ avec HTML5

Accélération matérielle

L'accélération matérielle est un jalon important pour les performances de rendu globales dans le navigateur. Le schéma général consiste à décharger les tâches qui seraient autrement calculées par le processeur principal sur le processeur graphique (GPU) de l'adaptateur graphique de votre ordinateur. Cela peut entraîner des gains de performances massifs et réduire 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 canevas
  • Dessin 3D WebGL

Bien que l'accélération du canevas et de WebGL soient des fonctionnalités à usage spécifique qui ne s'appliquent pas nécessairement à votre application, les trois premiers aspects peuvent aider à accélérer presque toutes les applications.

Que peut-on accélérer ?

L'accélération GPU consiste à transférer des tâches bien définies et spécifiques vers du matériel dédié. Le schéma général est le suivant : votre document est divisé en plusieurs "couches" qui sont invariables par rapport aux aspects de votre page accélérés. Ces calques sont affichés à l'aide du pipeline de rendu traditionnel. Le GPU est ensuite utilisé pour composer les calques sur une seule page en appliquant les "effets" pouvant être accélérés instantanément. Il est possible qu'un objet animé à l'écran ne nécessite pas de "remise en page" de la page pendant l'animation.

Vous devez donc vous assurer que le moteur de rendu peut facilement identifier quand il peut appliquer son accélération GPU. Prenons l'exemple suivant :

Bien que cela fonctionne, le navigateur ne sait pas vraiment que vous effectuez une action censée être perçue comme une animation fluide par un être humain. Réfléchissez à ce qui se passe lorsque vous obtenez le même aspect visuel à l'aide de transitions CSS3:

La façon dont le navigateur implémente cette animation est complètement masquée 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.

Chrome propose deux options de ligne de commande utiles pour faciliter le débogage de l'accélération du GPU:

  1. --show-composited-layer-borders affiche une bordure rouge autour des éléments manipulés au niveau du GPU. Permet de vérifier que vos manipulations se produisent dans la couche GPU.
  2. --show-paint-rects Toutes les modifications non GPU sont peintes, ce qui génère une bordure claire autour de toutes les zones repeintes. Vous pouvez voir le navigateur optimiser les zones de peinture en action.

Safari dispose d'options d'exécution similaires, décrites ici.

Transitions CSS3

Les transitions CSS rendent l'animation de style simple pour tous, mais elles sont également une fonctionnalité de performances intelligente. É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 par le matériel. Actuellement, WebKit (Chrome, Safari, iOS) propose des transformations CSS accélérées par matériel, mais cette fonctionnalité sera bientôt disponible dans d'autres navigateurs et plates-formes.

Vous pouvez utiliser des événements transitionEnd pour créer des combinaisons puissantes dans un script, mais pour le moment, la capture de tous les événements de fin de transition compatibles implique de 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 enhanced.

CSS3 Translate

Vous avez certainement déjà animé la position X/Y d'un élément sur la page. Vous avez probablement manipulé les propriétés "left" et "top" 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 option 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 transformations CSS 2D et les transitions CSS. Si c'est le cas, nous utiliserons translate pour modifier la position. S'il est animé à l'aide d'une transition, il est probable que le navigateur puisse l'accélérer matériellement. Pour inciter le navigateur à aller dans la bonne direction, nous allons utiliser la "baleine CSS magique" ci-dessus.

Si notre navigateur est moins performant, nous utiliserons jQuery pour déplacer notre élément. Vous pouvez utiliser le plug-in de polyfill jQuery Transform de Louis-Remi Babe pour automatiser l'ensemble.

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 dans un seul cycle de reflow et de redessin, ce qui permet d'obtenir une animation plus fidèle. Par exemple, les animations basées sur JavaScript synchronisées avec des transitions CSS ou des fichiers SMIL SVG. De plus, si vous exécutez la boucle d'animation dans un onglet qui n'est pas visible, le navigateur ne la maintient pas en cours d'exécution. Cela signifie que le processeur, le GPU et la mémoire sont moins utilisés, ce qui allonge considérablement l'autonomie de la batterie.

Pour en savoir plus sur l'utilisation de requestAnimationFrame et sur les raisons de l'utiliser, consultez l'article requestAnimationFrame pour une animation intelligente de Paul Irish.

Profilage

Lorsque vous découvrez que la vitesse de votre application peut être améliorée, il est temps de vous pencher sur le profilage pour identifier les optimisations qui pourraient apporter le plus d'avantages. Les optimisations ont souvent un impact négatif sur la maintenabilité de votre code source. Elles ne doivent donc être appliquées que si nécessaire. Le profilage vous indique les parties de votre code qui bénéficieraient le plus d'une amélioration de leurs performances.

Profilage JavaScript

Les profileurs JavaScript vous donnent un aperçu des performances de votre application au niveau des fonctions JavaScript en mesurant le temps nécessaire pour exécuter chaque fonction individuelle de son début à sa 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 indiquent généralement le temps nécessaire à l'exécution de toutes les invocations, 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 forte influence sur la fluidité et la réactivité de votre application. Il est important de comprendre que, même si les profileurs JavaScript mesurent le temps d'exécution de votre code JavaScript, ils mesurent également indirectement le temps passé à effectuer des opérations DOM. Ces opérations DOM sont souvent à l'origine de vos 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. Il est toujours très probable que la fonction drawArray s'affiche dans vos profils, car elle interagit de manière très coûteuse avec le DOM.

Conseils et astuces

Fonctions anonymes

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

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

rewrite to:

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

Il n'est pas courant de savoir que JavaScript permet de nommer des 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 lexical actuel. Cela peut écraser d'autres symboles. Faites donc attention.

Profilage des fonctions longues

Imaginez que vous avez une fonction longue et que vous soupçonnez qu'une petite partie de celle-ci pourrait être à l'origine de vos problèmes de performances. Il existe deux façons de déterminer la partie en cause:

  1. Méthode correcte: refactorisez votre code pour qu'il n'inclue aucune fonction longue.
  2. La méthode maléfique pour faire avancer les choses: ajoutez des instructions sous la forme de fonctions auto-appelantes nommées à votre code. Si vous êtes un peu prudent, cela ne modifie pas la sémantique et permet à certaines parties de votre fonction d'apparaître comme des fonctions individuelles dans le profileur : js function myLongFunction() { ... (function doAPartOfTheWork() { ... })(); ... } N'oubliez pas de supprimer ces fonctions supplémentaires une fois le profilage terminé, ou même de les utiliser comme point de départ pour refactoriser votre code.

Profilage du DOM

Les derniers outils de développement de l'outil d'inspection Web Chrome contiennent la nouvelle vue "Chronologie", qui affiche une chronologie des actions de bas niveau 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 quantité immense d'informations. Vous devez donc essayer de créer des scénarios de test minimaux que vous pouvez exécuter indépendamment.

Profilage du 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 indique 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 les aspects

Lorsque vous souhaitez profiler votre application, essayez de déterminer le plus précisément possible les aspects de sa fonctionnalité susceptibles de déclencher des ralentissements. Essayez ensuite d'exécuter un profil qui n'exécute que les parties de votre code 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 à des chemins de code sans rapport avec votre problème réel. Voici quelques exemples d'aspects individuels de votre application:

  1. Délai de démarrage (activation du profileur, rechargement de l'application, attente de l'initialisation, arrêt du profileur).
  2. Cliquez sur un bouton et sur l'animation qui s'affiche (lancez le profileur, cliquez sur le bouton, attendez que l'animation soit terminée, arrêtez le profileur).
Profilage de l'IUG

Exécuter uniquement la partie appropriée de votre application peut être plus difficile dans un programme d'IUG que lorsque vous optimisez, par exemple, le traçage de rayons de votre moteur 3D. Par exemple, si vous souhaitez profiler ce qui se passe lorsque vous cliquez sur un bouton, vous pouvez déclencher des événements de survol sans rapport qui rendent vos résultats moins concluants. Essayez de ne pas le faire.

Interface programmatique

Une interface programmatique permet également d'activer le débogueur. Cela permet de contrôler précisément le début et la fin du profilage.

Démarrez un profilage avec:

console.profile()

Arrêtez le profilage avec:

console.profileEnd()

Reproductibilité

Lorsque vous effectuez un profilage, assurez-vous de pouvoir reproduire vos résultats. Vous pourrez ainsi déterminer si vos optimisations ont réellement amélioré les performances. Le profilage au niveau de la fonction est également effectué dans le contexte de l'ensemble de votre ordinateur. Il ne s'agit pas d'une science exacte. Les exécutions de profils individuelles peuvent être influencées par de nombreux autres éléments sur votre ordinateur:

  1. Un minuteur sans rapport dans votre propre application qui se déclenche lorsque vous mesurez autre chose.
  2. Le garbage collector effectue son travail.
  3. Un autre onglet de votre navigateur effectuant un travail intensif dans le même thread d'exécution.
  4. Un autre programme sur 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 dans une même session de profilage. Vous réduisez ainsi l'influence des facteurs ci-dessus, et les parties lentes peuvent ressortir encore plus clairement.

Mesurez, améliorez, mesurez

Lorsque vous avez identifié un point lent dans votre programme, essayez de trouver des moyens d'améliorer le comportement d'exécution. Après avoir modifié votre code, effectuez à nouveau la procédure de profilage. Si vous êtes satisfait du résultat, passez à la suite. Si vous ne constatez aucune amélioration, vous devriez probablement annuler votre modification et ne pas la laisser "parce que ça ne peut pas faire de mal".

Stratégies d'optimisation

Réduire l'interaction avec le DOM

Pour améliorer la vitesse des applications clientes Web, il est courant de réduire l'interaction DOM. Bien que la vitesse des moteurs JavaScript ait augmenté d'un ordre de grandeur, l'accès au DOM n'a pas été accéléré au même rythme. Pour des raisons très pratiques, cela ne se produira jamais (la mise en page et le dessin d'éléments à l'écran prennent du temps).

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, essayez de déterminer si vous pouvez les réutiliser dans un calcul ultérieur (ou même simplement dans l'itération suivante de la boucle). Tant que vous n'ajoutez ni ne supprimez pas de nœuds dans la zone concernée, c'est souvent le cas.

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 des attributs

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

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 calcul des nombres réels du travail avec le DOM. Il est souvent possible d'effectuer un calcul, puis d'appliquer 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('');

Redessin et réajustement

Comme indiqué précédemment, l'accès au DOM est relativement lent. Il devient très lent lorsque votre code lit une valeur qui doit être recalculée, car votre code a récemment modifié quelque chose en rapport avec le DOM. Il est donc préférable d'éviter de mélanger les accès en lecture et en écriture au DOM. Dans l'idéal, votre code doit toujours être regroupé en deux phases:

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

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

  • Phase 1: Lire les valeurs DOM
  • Phase 2: Modifier le DOM
  • Phase 3: Lire plus
  • Phase 4: Modifiez le DOM ailleurs.

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);
}

Tenez compte de ce conseil 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'intervalle ou lors de la gestion d'une réponse ajax).

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

paintSlow()

Passer à l'implémentation plus rapide génère cette image:

Implémentation plus rapide

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

En savoir plus : Rendering: repaint, reflow/relayout, restyle (Rendu : recoloration, reflow/relayout, restyle) par Stoyan Stefanov

Redessins et boucle d'événements

L'exécution JavaScript dans le navigateur suit un modèle de "boucle d'événements". Par défaut, le navigateur est à l'état "inactif". Cet état peut être interrompu par des événements provenant d'interactions utilisateur ou d'éléments tels que des minuteurs JavaScript ou des rappels Ajax. Chaque fois qu'un code JavaScript s'exécute à un tel point d'interruption, le navigateur attend généralement qu'il se termine pour qu'il redessine l'écran (il peut y avoir des exceptions pour les codes JavaScript extrêmement longs ou dans des cas tels que les boîtes d'alerte qui interrompent effectivement l'exécution JavaScript).

Conséquences

  1. Si l'exécution des cycles d'animation JavaScript prend plus de 1/30 seconde, vous ne pourrez pas créer d'animations fluides, car le navigateur ne se redessinera pas pendant l'exécution du code JavaScript. Si vous prévoyez également de gérer les événements utilisateur, vous devez être beaucoup plus rapide.
  2. Il est parfois utile de retarder certaines actions JavaScript jusqu'à un peu plus tard. Par exemple, setTimeout(function() { ... }, 0) Cela indique au navigateur d'exécuter le rappel dès que la boucle d'événements est à nouveau inactive (certains navigateurs attendent au moins 10 ms). Sachez que cela créera deux cycles d'exécution JavaScript très proches dans le temps. Les deux peuvent déclencher un nouveau rebadigeon de l'écran, ce qui peut doubler le temps total passé à peindre. Le fait que cela déclenche réellement deux peintures dépend des heuristiques du navigateur.

Version standard:

function paintFast() {
  var height1 = $('#thing1').css('height');
  var height2 = $('#thing2').css('height');
  $('#otherThing1').css('height', '20px');
  $('#otherThing2').css('height', '20px');
}
Redessins 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)
}
Délai

La version retardée montre que le navigateur effectue deux opérations de peinture, même si les deux modifications apportées à la page ne sont espacées que d'un centième de seconde.

Initialisation différée

Les utilisateurs veulent que les applications Web se chargent rapidement et soient réactives. Toutefois, les utilisateurs ont des seuils différents pour ce qu'ils perçoivent comme lent, 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 de la souris, car cela pourrait créer une mauvaise expérience utilisateur pendant que l'utilisateur continue de déplacer sa souris. Toutefois, les utilisateurs sont habitués à accepter un léger 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énements

Répartir les gestionnaires d'événements sur une page peut prendre un temps relativement long et peut également être fastidieux 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.

La solution consiste à utiliser une technique appelée délégation d'événements. Au lieu d'associer des gestionnaires d'événements individuels à des éléments, la nature de remontée de nombreux événements du 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 s'il présente un intérêt.

En jQuery, vous pouvez facilement exprimer cela comme suit:

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

Cas pour lesquels la délégation d'événements n'est pas recommandée

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

Problèmes courants et solutions

Les tâches que j'effectue dans $(document).ready prennent beaucoup de temps

Conseil personnel de Malte: Ne faites jamais rien dans $(document).ready. Essayez de fournir votre document dans sa forme finale. OK, vous êtes autorisé à enregistrer des écouteurs d'événements, mais uniquement à l'aide d'un 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 de survol de l'élément concerné).

Si vous devez vraiment effectuer des actions, comme envoyer une requête Ajax pour obtenir des données réelles, affichez une animation agréable. Vous pouvez inclure l'animation en tant qu'URI de données s'il s'agit d'un GIF animé ou d'un élément similaire.

Depuis que j'ai ajouté un film Flash à la page, tout est très lent

Ajouter Flash à une page ralentit toujours un peu 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. Lorsque vous ne pouvez pas complètement éviter d'utiliser Flash sur vos pages, assurez-vous de définir le paramètre Flash "wmode" sur la valeur "window" (qui est la valeur par défaut). Cette option désactive la possibilité de composer des éléments HTML et Flash (vous ne pourrez pas voir d'élément HTML situé au-dessus du film Flash, et votre film Flash ne pourra pas être transparent). Cela peut être gênant, mais cela améliorera considérablement vos performances. Par exemple, observez comment youtube.com évite soigneusement de placer des calques au-dessus du lecteur vidéo principal.

J'enregistre des éléments dans localStorage. Maintenant, mon application saccade.

L'écriture dans localStorage est une opération synchrone qui implique de démarrer votre disque dur. Vous ne devez jamais effectuer d'opérations synchrones "longues" pendant les animations. Déplacez l'accès à localStorage à 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 qu'un 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 le tester dans la console JavaScript. En cas d'exception, réécrivez votre sélecteur pour ne pas utiliser d'extension spéciale de votre framework JavaScript. Cela accélérera votre sélecteur d'un ordre de grandeur dans les navigateurs modernes.

Si le problème persiste ou si vous souhaitez également accélérer le processus dans les navigateurs modernes, suivez ces consignes:

  • Soyez aussi précis que possible sur la droite de votre sélecteur.
  • Utilisez un nom de balise que vous n'utilisez pas souvent comme partie la plus à droite du sélecteur.
  • Si rien ne fonctionne, envisagez de réécrire le code afin de pouvoir utiliser un sélecteur d'ID.

Toutes ces manipulations DOM prennent beaucoup de temps

Un grand nombre d'insertions, de suppressions et de mises à jour de nœuds DOM peut être très lent. Cela peut généralement être optimisé en générant une longue chaîne HTML et en utilisant domNode.innerHTML = newHTML pour remplacer l'ancien contenu. Notez que cela peut être très mauvais pour la maintenance et peut créer des liens de mémoire dans IE. Faites donc attention.

Un autre problème courant est que votre code d'initialisation peut créer beaucoup de code HTML. Par exemple, un plug-in jQuery qui transforme une zone de sélection en un tas de divs, car c'est ce que les concepteurs voulaient, ignorant les bonnes pratiques en matière d'expérience utilisateur. Si vous voulez vraiment que votre page soit rapide, ne faites jamais cela. Transmettez plutôt tout le balisage côté serveur sous sa forme finale. Cette approche présente également de nombreux problèmes. Réfléchissez donc bien à l'intérêt de la vitesse.

Outils

  1. JSPerf : analyse des performances de petits extraits de code JavaScript
  2. Firebug : pour le profilage dans Firefox
  3. Outils Google Chrome pour les développeurs (disponibles sous forme de WebInspector dans Safari)
  4. DOM Monster : pour optimiser les performances du DOM
  5. DynaTrace Ajax Edition : pour le profilage et l'optimisation de la peinture dans Internet Explorer

Documentation complémentaire

  1. Google Speed
  2. Paul Irish sur les performances jQuery
  3. Performances JavaScript extrêmes (diapositives)