La reproduction non autorisée est interdite
1. Traitement de calculs coûteux
L’aspect le plus complexe du développement d’applications Javascript complexes est peut-être la nature monothread de l’interface utilisateur. La meilleure situation lorsque Javascript gère l'interaction de l'utilisateur est une réponse lente, et la pire situation est une absence de réponse provoquant le blocage du navigateur (lorsque Javascript est exécuté, toutes les opérations de mise à jour de la page sont suspendues). De ce fait, il est impératif de réduire toutes les opérations complexes (tout calcul de plus de 100 ms) à un niveau gérable. De plus, si le script ne s'arrête pas après avoir été exécuté pendant au moins 5 secondes, certains navigateurs (tels que Firefox et Opera) génèrent une boîte de dialogue pour avertir l'utilisateur que le script ne répond pas.
Ceci n’est évidemment pas souhaitable, et produire une interface qui ne répond pas n’est pas une bonne chose. Cependant, c'est presque certainement le cas lorsque vous devez traiter de grandes quantités de données (par exemple, traiter des milliers d'éléments DOM).
A cette époque, la minuterie est particulièrement utile. Étant donné que le minuteur peut effectivement suspendre l'exécution du code Javascript, il peut également empêcher le navigateur de suspendre le code en cours d'exécution (tant que le code individuel ne suffit pas à provoquer le blocage du navigateur). Dans cet esprit, nous pouvons incorporer des calculs de boucle normaux et intensifs dans des calculs non bloquants. Regardons l'exemple suivant où ce type de calcul est requis.
Une tâche de longue haleine :
<table><tbody></tbody></table>
// Fonctionnement normal, intensif
var table = document.getElementsByTagName("tbody");
pour ( var je = 0; je < 2000; je++ ) {
var tr = document.createElement("tr");
pour ( var t = 0; t < 6; t++ ){
var td = document.createElement("td");
td.appendChild(document.createTextNode("" + t));
tr.appendChild(td);
}
table.appendChild(tr);
}
}
Dans cet exemple, nous créons un total de 26 000 nœuds DOM et remplissons les nombres dans un tableau. Cela coûte trop cher et bloquera très probablement le navigateur et empêchera l'interaction normale de l'utilisateur. Nous pouvons introduire des minuteries et obtenir des résultats différents, peut-être meilleurs.
Utilisez des minuteries pour interrompre les tâches de longue durée :
<table><tbody></tbody></table>
var table = document.getElementsByTagName("tbody");
var je = 0, max = 1999 ;
setTimeout(fonction(){
pour ( var étape = i + 500; i < étape; i++ ) {
var tr = document.createElement("tr");
pour ( var t = 0; t < 6; t++ ){
var td = document.createElement("td");
td.appendChild(document.createTextNode("" + t));
tr.appendChild(td);
}
}
table.appendChild(tr);
}
si ( je < max )
setTimeout( arguments.callee, 0 );
}, 0);
Dans notre exemple modifié, nous divisons le calcul intensif en quatre parties, chacune créant 6 500 nœuds. Il est peu probable que ces calculs interrompent le flux normal du navigateur. Le pire des cas est que ces nombres puissent être ajustés à tout moment (par exemple, faites-les varier entre 250 et 500, afin que chacune de nos cellules génère 3 500 nœuds DOM). Mais ce qui est le plus impressionnant, c'est la manière dont nous avons modifié notre code pour l'adapter au nouveau système asynchrone. Nous devons faire davantage de travail pour garantir que les nombres des éléments sont générés correctement (la boucle ne se termine pas éternellement). Le code est très similaire à notre code original. Notez que nous utilisons des fermetures pour maintenir l'état d'itération entre les fragments de code. Sans fermetures, ce code sera sans aucun doute plus complexe.
Il y a un net changement en utilisant cette technologie par rapport à l'original. Les longs blocages du navigateur sont remplacés par 4 mises à jour visuelles des pages. Bien que le navigateur essaie d'exécuter ces extraits de code le plus rapidement possible, il restitue également les modifications du DOM (comme des mises à jour massives) après chaque étape du minuteur. Dans la plupart des cas, les utilisateurs ne sont pas au courant de ces types de mises à jour, mais il est important de se rappeler qu'elles se produisent.
Il existe une situation dans laquelle cette technologie fonctionnerait spécifiquement pour moi : une application que j'ai créée pour calculer les horaires des étudiants. Au début, l'application était typique de CGI (le client parlait au serveur, le serveur calculait le planning et le renvoyait). Mais je l'ai modifié et mis tous les calculs de planning sur le client. Voici la vue des calculs de planning :
Ces calculs sont assez coûteux (des milliers de permutations doivent être parcourues pour trouver la bonne réponse). Ce problème est résolu en divisant le calcul du planning en unités réelles (mise à jour de l'interface utilisateur avec la pièce terminée). En fin de compte, les utilisateurs ont fourni une interface utilisateur rapide, réactive et utilisable.
Il est souvent surprenant de constater à quel point la technologie peut être utile. Vous le trouverez souvent utilisé dans des programmes de longue durée, comme les boîtes de test (nous en discutons à la fin de ce chapitre). Plus important encore, cette technologie nous montre à quel point il est facile de contourner les limitations de l'environnement du navigateur tout en offrant aux utilisateurs une expérience riche.