Préface
Que le code JavaScript actuel soit intégré ou dans un fichier de lien externe, le téléchargement et le rendu de la page doivent être arrêtés et attendre l'exécution du script. Plus le processus d'exécution JavaScript est long, plus le navigateur attend la réponse à l'entrée de l'utilisateur. La raison pour laquelle les navigateurs bloquent lors du téléchargement et de l'exécution de scripts est que les scripts peuvent modifier l'espace de noms de la page ou JavaScript, ce qui affecte le contenu des pages suivantes. Un exemple typique consiste à utiliser document.write() dans une page, comme la liste 1
Listing 1 Code JavaScript Exemple intégré
<html> <éad- head> <ititle> Exemple source </ title> </ head> <body> <p> <script type = "text / javascript"> document.write ("aujourd'hui est" + (new date ()). todateString ()); </cript> </p> </ body> </html>Lorsque le navigateur rencontre une balise <cript>, la page HTML actuelle n'a aucun moyen de savoir si JavaScript ajoutera du contenu à la balise <p>, introduire d'autres éléments ou même supprimer la balise. Par conséquent, pour le moment, le navigateur cessera de traiter la page, exécutera d'abord le code JavaScript, puis continuera à analyser et à rendre la page. La même chose se produit lors du chargement JavaScript à l'aide de la propriété SRC. Le navigateur doit d'abord prendre le temps de télécharger le code dans le fichier de lien externe, puis de l'analyser et de l'exécuter. Au cours de ce processus, le rendu des pages et l'interaction utilisateur sont complètement bloqués.
Emplacement du script
La spécification HTML 4 indique que les balises <cript> peuvent être placées dans <Aad> ou <body> des documents HTML et peuvent apparaître plusieurs fois. Les développeurs Web sont généralement habitués au chargement du lien externe JavaScript dans <Aadred>, puis à l'utilisation de la balise <ink> pour charger des fichiers CSS de liaison externe ou d'autres informations de page. Par exemple, listing 2
Listing 2 Exemple d'emplacements de script inefficaces
<html> <éad- head> <ititle> Exemple source </ title> <script type = "text / javascript" src = "script1.js"> </ script> <script type = "text / javascript" src = "script2.js"> </ script> <script type = "Text / javascript" src = "script2.js"> </cript> <script> <script = "Script =" Text / javascrip src = "script3.js"> </ script> <link rel = "Stylesheet" type = "text / css" href = "Styles.css"> </ head> <pody> <p> bonjour world! </p> </ body> </html>
Cependant, cette approche conventionnelle cache de graves problèmes de performance. Dans l'exemple de Listing 2, lorsque le navigateur analyse la balise <cript> (ligne 4), le navigateur cesse d'analyser le contenu suivant et hiérarchise le téléchargement du fichier de script et l'exécution du code, ce qui signifie que le fichier de style Styles.css.css ultérieur ni le body> ne peut être chargé. Étant donné que la balise <body> ne peut pas être chargée, la page ne sera naturellement pas rendue. Par conséquent, la page est vide jusqu'à ce que le code JavaScript soit entièrement exécuté. La figure 1 décrit le processus de téléchargement des scripts et des fichiers de style pendant le chargement de la page.
Figure 1 Chargement et exécution des fichiers JavaScript bloquant le téléchargement d'autres fichiers
Nous pouvons trouver un phénomène intéressant: le premier fichier JavaScript commence à télécharger, tout en bloquant le téléchargement d'autres fichiers sur la page. De plus, il y a un retard avant la fin du téléchargement Script1.js et Script2.js commence à télécharger, qui se trouve être le processus d'exécution du fichier script1.js. Chaque fichier doit attendre que le fichier précédent soit téléchargé et exécuté avant de commencer le téléchargement. Lors du téléchargement de ces fichiers un par un, l'utilisateur voit une page vierge.
En commençant par IE 8, Firefox 3.5, Safari 4 et Chrome 2, tous permettent de télécharger des fichiers JavaScript en parallèle. C'est une bonne nouvelle car la balise <Script> ne bloque pas d'autres balises <cript> lors du téléchargement des ressources externes. Malheureusement, le processus de téléchargement JavaScript bloquera toujours le téléchargement d'autres ressources, tels que les fichiers de style et les images. Bien que le processus de téléchargement du script ne se affecte pas, la page doit toujours attendre que tous les code JavaScript soient téléchargés et exécutés avant de pouvoir continuer. Ainsi, bien que les derniers navigateurs améliorent les performances en permettant des téléchargements parallèles, le problème n'a pas été complètement résolu et le blocage des scripts reste un problème.
Étant donné que les scripts bloquent les téléchargements d'autres ressources sur la page, il est recommandé de placer toutes les balises <cript> en bas des balises <body> autant que possible pour minimiser l'impact sur l'ensemble du téléchargement de la page. Par exemple, énumérer 3
Listing 3 Exemple de placement de code recommandé
<Html> <A-Head> <Title> Exemple source </ title> <link rel = "Stylesheet" type = "Text / CSS" href = "Styles.css"> </ head> <body> <p> Bonjour monde type = "text / javascript" src = "script2.js"> </ script> src = "script3.js"> </ script> </ body> </html>
Ce code montre l'emplacement recommandé pour placer des balises <cript> dans des documents HTML. Bien que les téléchargements de scripts bloquent un autre script, la majeure partie de la page a été téléchargée et affichée à l'utilisateur, de sorte que le téléchargement de la page n'apparaîtra pas trop lentement. Il s'agit de la première règle pour optimiser JavaScript: mettez le script en bas.
Organiser les scripts
Étant donné que chaque balise <cript> est bloquée lorsque la page est initialement téléchargée, la réduction du nombre de balises <cript> incluses sur la page aide à améliorer cette situation. Ce n'est pas seulement pour les scripts de liaison externe, mais aussi pour le nombre de scripts intégrés. Chaque fois qu'un navigateur rencontre une balise <cript> pendant l'analyse d'une page HTML, elle entraînera un certain retard en raison de l'exécution du script, donc la minimisation du temps de retard améliorera considérablement les performances globales de la page.
Ce problème est légèrement différent lorsqu'il s'agit de fichiers JavaScript externes. Étant donné les frais généraux de performances supplémentaires des demandes HTTP, le téléchargement d'un seul fichier de 100KB sera plus rapide que le téléchargement de 5 fichiers de 20KB. Autrement dit, la réduction du nombre de scripts de liaison externe dans la page améliorera les performances.
Habituellement, un grand site Web ou une application doit s'appuyer sur plusieurs fichiers JavaScript. Vous pouvez fusionner plusieurs fichiers en un seul, afin que vous n'ayez besoin que de référencer une balise <cript> pour réduire la consommation de performances. La fusion de fichiers peut être réalisée via des outils d'emballage hors ligne ou des services en ligne en temps réel.
Il convient de noter que la mise en place d'un script intégré après avoir fait référence à la feuille de style de liaison externe provoquera le blocage de la page et attendra le téléchargement de la feuille de style. Ceci est fait pour s'assurer que les scripts intégrés peuvent obtenir les informations de style les plus précises lors de l'exécution. Par conséquent, il est recommandé de ne pas suivre les scripts embarqués immédiatement après la balise <ink>.
Scripts non bloquants
La réduction de la taille du fichier JavaScript et limitant les demandes HTTP n'est pas toujours possible sur les applications Web riches en fonctionnalités ou les grands sites Web. Plus une application Web est de fonctionnalités, plus il a besoin de code JavaScript. Bien que le téléchargement d'un seul fichier JavaScript plus grand ne génère une demande HTTP uniquement, il verrouillera le navigateur pendant longtemps. Pour éviter cela, il est nécessaire de charger progressivement les fichiers JavaScript dans la page via certaines techniques spécifiques, de sorte que dans une certaine mesure, il ne bloque pas le navigateur.
Le secret pour débloquer les scripts est que le code JavaScript n'est chargé qu'après le chargement de la page. Cela signifie télécharger le script après que l'événement Onload de l'objet Window a été licencié. Il existe un certain nombre de façons d'atteindre cet effet.
Retarder les scripts de chargement
HTML 4 définit un attribut étendu pour la balise <cript>: différer. L'attribut de différence indique que le script contenu dans cet élément ne modifie pas le DOM, donc le code peut être retardé en toute sécurité. L'attribut de repère n'est pris en charge que par les navigateurs IE 4 et Firefox 3.5 ultérieurs, ce n'est donc pas une solution de navigateur intermédiaire idéale. Dans d'autres navigateurs, l'attribut de report est ignoré directement, de sorte que la balise <cript> sera traitée de la manière par défaut, ce qui signifie qu'elle entraînera un blocage. Cependant, il s'agit toujours d'une solution utile si votre navigateur cible le prend en charge. Listing 4 est un exemple
Listing 4 Exemple de méthode d'utilisation des attributs de report
<script type = "text / javascript" src = "script1.js" Defer> </ script>
La balise <cript> avec l'attribut de différence peut être placée n'importe où dans le document. Le fichier JavaScript correspondant commencera à télécharger lorsque la page sera analysée à la balise <cript>, mais ne sera pas exécutée tant que le DOM se charge, c'est-à-dire que l'événement Onload sera licencié. Lorsqu'un fichier JavaScript avec l'attribut de report est téléchargé, il ne bloque pas d'autres processus dans le navigateur, de sorte que ces fichiers peuvent être téléchargés en parallèle avec d'autres fichiers de ressources.
Tout élément <cript> avec l'attribut de report ne sera exécuté que lorsque le DOM sera chargé, que ce soit des scripts intégrés ou externes. L'exemple dans Listing 5 montre comment l'attribut de différence affecte le comportement du script:
Listing 5 L'effet de l'attribut de différence sur le comportement du script
<html> <éad- head> <itle> Exemple de différence de script </tapt> </ head> <body> <script type = "text / javaScript" Defer> alert ("reférer"); </ script> <script type = "text / javascript"> alert ("script"); </ script> <script type = "text / javaScript"> window.onload = function () {alert ("charg"); }; </cript> </ body> </html>Ce code apparaît trois boîtes de dialogue lors du traitement de la page. L'ordre pop-up des navigateurs qui ne prennent pas en charge l'attribut de différence est: "différer", "script" et "charger". Sur les navigateurs qui prennent en charge l'attribut de différence, l'ordre pop-up est: "script", "différer" et "charger". Notez que l'élément <cript> avec l'attribut de différence n'est pas exécuté après le second, mais qu'il est appelé avant le déclenchement de l'événement Onload.
Si votre navigateur cible comprend uniquement Internet Explorer et Firefox 3.5, le script de différence est en effet utile. Si vous devez prendre en charge plusieurs navigateurs dans les domaines, il existe des moyens plus cohérents de l'implémenter.
HTML 5 définit un nouvel attribut étendu pour le <cript> tag: async. Sa fonction est la même que celle de report, et il peut charger et exécuter des scripts de manière asynchrone, sans bloquer le chargement de la page en raison des scripts de chargement. Cependant, une chose à noter est que dans le cas d'Async, les scripts JavaScript seront exécutés une fois qu'ils seront téléchargés, il est donc très probable qu'ils ne soient pas exécutés dans l'ordre d'origine. S'il y a des dépendances avant et après les scripts JavaScript, il est très probable qu'une erreur se produira en utilisant Async.
Éléments de script dynamique
Le modèle d'objet de document (DOM) vous permet de créer dynamiquement presque tous les contenus de document de HTML à l'aide de JavaScript. L'élément <cript>, comme les autres éléments de la page, peut être créé très facilement avec des fonctions DOM standard:
Listing 6 Créer des éléments <cript> avec des fonctions DOM standard
var script = document.createElement ("script"); script.type = "text / javascript"; script.src = "script1.js"; document.getElementsByTagName ("Head") [0] .APPEndChild (script);Le nouvel élément <cript> charge le fichier source script1.js. Téléchargez ce fichier immédiatement après l'ajout de l'élément à la page. Le point clé de cette technologie est que peu importe où le téléchargement est démarré, le téléchargement et l'exécution du fichier ne bloqueront pas d'autres traitements de page. Vous pouvez même placer ces codes dans la section <Aad> sans affecter le code de page pour le reste (à l'exception des connexions HTTP utilisées pour télécharger des fichiers).
Lorsqu'un fichier est téléchargé à l'aide d'un nœud de script dynamique, le code retourné est généralement exécuté immédiatement (sauf Firefox et Opera, il attendra que tous les nœuds de script dynamique précédents terminent l'exécution). Ce mécanisme fonctionne bien lorsque le script est du type "auto-pilote", mais si le script ne contient que des interfaces pour l'invocation d'autres scripts sur la page, il causera des problèmes. Dans ce cas, vous devez suivre si le téléchargement du script est terminé et s'il est prêt. Vous pouvez utiliser des nœuds <cript> dynamiques pour émettre des événements pour obtenir des informations pertinentes.
Firefox, Opera, Chorme et Safari 3+ publieront un événement Onload une fois la réception du nœud <cript>. Vous pouvez écouter cet événement pour préparer les notifications par le script:
Listing 7 Chargement des scripts JavaScript en écoutant les événements Onload
var script = document.createElement ("script") script.type = "text / javascript"; // firefox, opéra, chrome, safari 3 + script.onload = function () {alert ("script chargé!");}; script.src = "script1.js"; document.getElementsByTagname ("Head") [0] .AppendChild (script);Internet Explorer prend en charge une autre implémentation qui émet un événement ReadyStateChange. L'élément <cript> a une propriété ReadyState dont la valeur change à mesure que le processus de téléchargement des fichiers externes. Il y a cinq valeurs pour ReadyState:
1. "Non initialisé": statut par défaut
2. "Chargement": le téléchargement commence
3. "Load": Télécharger terminé
4. "Interactive": le téléchargement est terminé mais pas encore disponible
5. "Compléter": toutes les données sont prêtes
La documentation Microsoft indique que pendant le cycle de vie de l'élément <cript>, ces valeurs de ReadyState peuvent ne pas apparaître, mais n'indiquent pas quelles valeurs seront toujours utilisées. En pratique, ce qui nous intéresse le plus, ce sont les états "chargés" et "complets". Internet Explorer n'a pas l'état final représenté par ces deux valeurs ReadyState. Parfois, l'élément <cript> obtiendra un "chargeur" mais jamais "complet", mais dans certains cas, "complet" apparaît et "chargé" ne peut pas être utilisé. Le moyen le plus sûr est de vérifier ces deux états dans l'événement ReadyStateChange, et lorsque l'un des États apparaît, supprimez la poignée de l'événement ReadyStateChange (assurez-vous que l'événement ne sera pas traité deux fois):
Listing 8 Chargement des scripts JavaScript en vérifiant l'état ReadyState
var script = document.createElement ("script") script.type = "text / javascript"; // Internet explororscript.onreadystatechange = function () {if (script.readystate == "chargé" || script.readystate == "complet") {script.onreadystatechange = null; alert ("script chargé."); }}; script.src = "script1.js"; document.getElementsByTagName ("head") [0] .APPENDCHILD (script);Dans la plupart des cas, vous souhaitez appeler une fonction pour implémenter le chargement dynamique des fichiers JavaScript. Les fonctions suivantes résument les fonctions requises par les implémentations standard et les implémentations IE:
Listing 9 encapsulation par fonction
fonction chargescript (url, callback) {var script = document.createElement ("script") script.type = "text / javascript"; if (script.readystate) {// ie script.onreadystatechange = function () {if (script.readystate == "chargé" || script.readystate == "complet") {script.onreadystatechange = null; callback (); }}; } else {// autres script.onload = function () {callback (); }; } script.src = url; document.getElementsByTagName ("Head") [0] .APPEndChild (script);}Cette fonction reçoit deux paramètres: l'URL du fichier JavaScript et une fonction de rappel qui est déclenchée lorsque la réception JavaScript est terminée. La vérification des attributs est utilisée pour déterminer l'événement à surveiller. Dans la dernière étape, définissez la propriété SRC et ajoutez l'élément <cript> à la page. Cette fonction LoadScript () est utilisée comme suit:
Listing 10 Comment utiliser la fonction LoadScript ()
LoadScript ("script1.js", function () {alert ("Le fichier est chargé!");});Vous pouvez charger dynamiquement de nombreux fichiers JavaScript sur la page, mais veillez à ce que le navigateur ne garantit pas l'ordre dans lequel les fichiers sont chargés. Parmi tous les principaux navigateurs, seuls Firefox et Opera garantissent que les scripts sont exécutés dans l'ordre que vous spécifiez. D'autres navigateurs téléchargeront et exécuteront différents fichiers de code dans l'ordre où le serveur les renvoie. Vous pouvez concaténer les opérations de téléchargement ensemble pour assurer leur commande, comme suit:
Listing 11 Chargez plusieurs scripts JavaScript via la fonction LoadScript ()
LoadScript ("script1.js", function () {loadscript ("script2.js", function () {loadscript ("script3.js", function () {alert ("tous les fichiers sont chargés!");});});}); });Ce code attend que Script1.js soit disponible avant de commencer à charger Script2.js, puis commencez à charger Script3.js après le script2.js est disponible. Bien que cette méthode soit possible, elle est toujours un peu gênante s'il existe de nombreux fichiers à télécharger et à exécuter. Si l'ordre de plusieurs fichiers est très important, une meilleure façon consiste à connecter les fichiers dans un seul fichier dans le bon ordre. Un fichier autonome peut télécharger tout le code à la fois (puisque cela est fait de manière asynchrone, il n'y a aucune perte à utiliser un grand fichier).
Le chargement dynamique du script est le modèle le plus couramment utilisé dans les téléchargements JavaScript non bloquants car il peut être un cross-navigateur et est facile à utiliser.
Utilisation de l'objet XMLHTTPREQUEST (XHR)
Cette technique crée d'abord un objet XHR, puis télécharge un fichier JavaScript, puis injecte le code JavaScript dans la page avec un élément dynamique <script>. Listing 12 est un exemple simple:
Listing 12 Chargement des scripts JavaScript via des objets XHR
var xhr = new xmlHttpRequest (); xhr.open ("get", "script1.js", true); xhr.onreadystateChange = function () {if (xhr.readystate == 4) {if (xhr.status> = 200 && xhr.statur <300 || xhr.status == 304) Document.CreateElement ("Script"); script.type = "text / javascript"; script.text = xhr.ResponSeText; document.body.appendChild (script); }}}; xhr.send (null);Ce code envoie une demande GET au serveur pour obtenir le fichier script1.js. Le gestionnaire d'événements OnreadyStateChange vérifie si ReadyState est 4, puis vérifie si le code d'état HTTP est valide (2xx signifie une réponse valide, 304 signifie une réponse en cache). Si une réponse valide est reçue, un nouvel élément <cript> est créé et son attribut de texte est défini sur la chaîne ResponseText reçue du serveur. Cela créera en fait un élément <cript> avec du code en ligne. Une fois le nouvel élément <cript> ajouté au document, le code sera exécuté et prêt à être utilisé.
Le principal avantage de cette approche est que vous pouvez télécharger le code JavaScript qui n'est pas exécuté immédiatement. Étant donné que le code revient en dehors de la balise <cript> (en d'autres termes, il n'est pas soumis à la balise <cript>), il ne sera pas exécuté automatiquement après le téléchargement, ce qui vous permet de reporter l'exécution jusqu'à ce que tout soit prêt. Un autre avantage est que le même code ne lance pas des exceptions dans tous les navigateurs modernes.
La principale limitation de cette méthode est que les fichiers JavaScript doivent être placés dans le même domaine que la page et ne peuvent pas être téléchargés à partir de CDN (CDN fait référence à "Network de livraison de contenu", de sorte que les grandes pages Web n'utilisent généralement pas la technologie d'injection de script XHR.
Ajoutez des fonctions que vous utilisez habituellement
fonction chargejs (url, rappel, charse) {var head = document.getElementsByTagName ("head") [0]; var script = document.createElement ("script"); if (!! charset) script.charset = "utf-8"; script.src = url; script.onload = script.onreadystatechange = function () {var f = script.readystate; if (f && f! = "chargé" && f! = "complet") return; script.onload = script.onreadystateChange = null; head.removechild (script) if (callback) {callback () || rappel}; }; head.appendChild (script);} // Fonction de chargement synchrone JS getScripts (i, linkarray, fn) {env || getenv (); var script = document.createElement ('script'); script.type = 'text / javascript'; script.src = linkArray [i]; var head = document.head || document.getElementsByTagName ('Head') [0]; head.appendChild (script); if (Env.ie && 'onReadyStateChange' dans Script &&! ('draggable' dans le script)) {// ie Browser charge script.onreadystatechange = function () {if (/loaded|complete/.Test(Script.readystate)) {script.onreadystatechange = null; if (i === linkArray.length-1) {if (fn) {fn (); }} else {getScripts (++ i, linkArray, fn); }}}}; } else {script.onload = function () {if (i === linkarray.length-1) {if (fn) {fn (); }} else {getScripts (++ i, linkArray, fn); }}}; }} // js a une dépendance Chargement GetScripts (0, ['http://caibaojian.com/demo/base.js', 'http://caibaojian.com/demo/reset.js'], function () {alert ('rappel');});Résumer
Il existe plusieurs façons de réduire l'impact des performances de JavaScript:
En mettant toutes les balises <cript> en bas de la page, c'est-à-dire avant de fermer la balise, cela garantit que la page a été rendue avant l'exécution du script.
Fusionner autant que possible les scripts. Moins des balises <cript> dans la page moins, plus il se chargera rapidement et plus il répondra rapidement. Cela est vrai pour les scripts externes et les scripts intégrés.
Utilisez des scripts JavaScript non bloqués à télécharger:
Utilisez l'attribut de différence de la balise <cript> (uniquement disponible pour IE et Firefox 3.5 ou plus);
Utilisez des éléments <cript> créés dynamiquement pour télécharger et exécuter du code;
Utilisez des objets XHR pour télécharger le code JavaScript et injecter dans la page.
Les stratégies ci-dessus peuvent considérablement améliorer les performances réelles des sites Web et des applications qui nécessitent beaucoup de JavaScript.
Ce qui précède est le contenu complet de la charge et de l'exécution du résumé d'optimisation des performances JavaScript. J'espère que ce sera utile à tout le monde.