Préface
Je crois que tout le monde a rencontré de nombreux problèmes concernant le chargement du script JavaScript. Principalement à plusieurs points -
1> Problèmes de chargement de fichiers, de dépendance au fichier et de l'ordre d'exécution causée par des scripts synchrones et des scripts asynchrones
2> Problèmes d'optimisation des performances causés par les scripts synchrones et les scripts asynchrones
Une compréhension approfondie de tous les aspects du chargement des scripts n'est pas seulement propice à la résolution de problèmes pratiques, mais également à la saisie et à l'exécution d'optimisation des performances.
Regardez d'abord n'importe quel code de balise de script -
La copie de code est la suivante:
<script src = "js / myapp.js"> </ script>
Si elle est placée sur <A-Head>, il bloquera tous les travaux de rendu de page, ce qui fait rester l'utilisateur dans un état "Écran blanc de mort" jusqu'à ce que le script soit chargé et exécuté. Le script à la fin de <body> ne permettra que l'utilisateur voir la page statique sans vitalité. Où le rendu du client est censé être dispersé avec des commandes inefficaces et des boîtes vides. Prenez un cas de test -
La copie de code est la suivante:
<! Doctype html>
<html>
<head lang = "en">
<meta charset = "utf-8">
<Title> Script de chargement asynchrone </TITME>
<script src = "js / test.js"> </ script>
</ head>
<body>
<div> je suis content </div>
<img src = "img / test.jpg">
</docy>
</html>
Parmi eux, le contenu de test.js -
La copie de code est la suivante:
alert («Je suis le code de script dans la tête. Après avoir exécuté le JS ici, le rendu du contenu corporel commence!»);
Nous verrons qu'Alert est un point de pause, et pour le moment, la page est vide. Cependant, sachez que toute la page a été chargée pour le moment. Si le corps contient des balises pour certains attributs SRC (comme la balise IMG ci-dessus), le navigateur a commencé à charger le contenu pertinent pour le moment. En bref, il convient de noter que le calendrier de travail du moteur JS et du moteur de rendu s'excluent mutuellement (certains livres l'appellent le fil d'interface utilisateur).
Par conséquent, nous avons besoin que les scripts qui sont responsables de la meilleure apparence et de l'utilisation de la page devraient être chargés immédiatement, et les scripts qui peuvent être chargés plus tard seront chargés plus tard.
1. Délai d'exécution du script
Maintenant, il devient de plus en plus populaire de placer des scripts à la fin de la balise Page <body>. De cette façon, d'une part, l'utilisateur peut voir la page plus rapidement et, d'autre part, le script peut utiliser directement les éléments DOM qui ont été chargés. Ce "mouvement" est une énorme amélioration pour la plupart des scripts. Le modèle de page est le suivant -
La copie de code est la suivante:
<! Doctype html>
<html>
<head lang = "en">
<! - Les métadonnées et les feuilles de script vont ici ->
<script src = "headscript.js"> </ script>
</ head>
<body>
<! - Le contenu va ici ->
<script src = "bodycript.js"> </ script>
</docy>
</html>
Cela accélère considérablement le temps de rendu de la page, mais sachez que cela peut donner aux utilisateurs la possibilité d'interagir avec la page avant le chargement du bodycrit. La raison pour laquelle le navigateur ne peut pas charger les scripts avant de charger le document complet est un gros goulot d'étranglement pour les grands documents transmis sur des connexions lentes.
Idéalement, le chargement du script doit être effectué simultanément avec le chargement du document et n'affecte pas le rendu du DOM. De cette façon, une fois le document prêt, le script peut être exécuté car le script correspondant a été chargé dans l'ordre de la balise <cript>.
Nous pouvons accomplir cette exigence en utilisant un repère, c'est-à-dire,
La copie de code est la suivante:
<script src = "DeferredScript.js"> </ script>
L'ajout de l'attribut de différence équivaut à dire au navigateur: veuillez commencer à charger ce script immédiatement, mais veuillez attendre que le document soit prêt et que tous les scripts avec l'attribut de repère aient fini de fonctionner avant de l'exécuter.
De cette façon, la mise en place de scripts de retard dans l'étiquette de tête apportera tous les avantages de placer des scripts sur l'étiquette corporelle, et il peut considérablement améliorer la vitesse de chargement des grands documents. Le mode page à l'heure actuelle est -
La copie de code est la suivante:
<! Doctype html>
<html>
<head lang = "en">
<! - Les métadonnées et les feuilles de script vont ici ->
<script src = "headscript.js"> </ script>
<script src = "DeferredScript.js" Defer> </ script>
</ head>
<body>
<! - Le contenu va ici ->
</docy>
</html>
Cependant, tous les navigateurs ne prennent pas en charge un repère (pour certains navigateurs modernes, si un report est déclaré, leurs scripts internes n'effectueront pas de documents. Cela signifie que si vous souhaitez vous assurer que votre script de retard peut s'exécuter après le chargement du document, vous devez encapsuler le code de tous les scripts de retard dans une structure telle que JQuery's $ (document) .ready. Cela en vaut la peine, car près de 97% des visiteurs peuvent profiter des avantages du chargement parallèle, tandis que 3% des visiteurs peuvent toujours utiliser JavaScript complet.
2. Parallélisation complète des scripts
Que les scripts soient chargés et exécutés plus rapidement une étape. Je ne veux pas attendre que les scripts de report l'exécutent les uns après les autres (différer nous rappelle un scénario de mise en file d'attente Je veux charger et exécuter ces scripts dès que possible. Ici, nous pensons à l'attribut asynchrone de HTML5, mais sachez qu'il s'agit d'une anarchie chaotique.
Par exemple, nous chargeons deux scripts tiers complètement non pertinents, et la page fonctionne bien sans eux, et nous ne nous soucions pas de savoir qui fonctionne en premier et qui fonctionne plus tard. Par conséquent, l'utilisation de l'attribut asynchrone sur ces scripts tiers équivaut à améliorer leur vitesse de course sans dépenser un sou.
L'attribut asynchrone est nouvellement ajouté à HTML5. La fonction est similaire à Defer, c'est-à-dire qu'elle permet le rendu DOM lors du téléchargement des scripts. Cependant, il sera exécuté dès que possible après le téléchargement (c'est-à-dire que le moteur JS est inactif et exécuté immédiatement), et rien ne garantit que le script sera exécuté dans l'ordre. Ils seront terminés avant l'événement Onload.
Firefox 3.6, Opera 10.5, IE 9, et le dernier Chrome et Safari prennent tous en charge l'attribut asynchrone. L'async et le report peuvent être utilisés en même temps, de sorte que tous les IE après IE 4 prennent en charge le chargement asynchrone, mais soyez prudent qu'Async écrasera le report.
Ensuite, le modèle de page à l'heure actuelle est le suivant -
La copie de code est la suivante:
<! Doctype html>
<html>
<head lang = "en">
<! - Les métadonnées et les feuilles de script vont ici ->
<script src = "headscript.js"> </ script>
<script src = "DeferredScript.js" Defer> </ script>
</ head>
<body>
<! - Le contenu va ici ->
<script src = "asyncscript1.js" Async Defer> </cript>
<script src = "asyncscript2.js" Async Defer> </cript>
</docy>
</html>
Faites attention à l'ordre d'exécution ici - chaque fichier de script est chargé, puis Headscript.js est exécuté, puis DefferedScript.js est chargé en arrière-plan pendant le rendu DOM. Ensuite, DefferedScript.js et les deux scripts asynchrones seront exécutés à la fin du rendu DOM. Notez que pour les navigateurs qui prennent en charge l'attribut asynchrone, ces deux scripts seront à la gamme de l'ordre.
3. Chargement du script programmable
Bien que les fonctions des deux propriétés de script ci-dessus soient très attrayantes, elles ne sont pas largement utilisées en raison de problèmes de compatibilité. Par conséquent, nous utilisons les scripts pour charger davantage d'autres scripts. Par exemple, nous voulons seulement charger un script pour les utilisateurs qui remplissent certaines conditions, qui sont le "chargement paresseux" souvent mentionné.
Au niveau de l'API du navigateur, il existe deux façons raisonnables de ramper et d'exécuter des scripts de serveur -
1> Générez une demande Ajax et utilisez la fonction EVAL pour traiter la réponse
2> Insérez la balise <cript> dans le DOM
Cette dernière méthode est meilleure car le navigateur s'inquiètera de générer des demandes HTTP pour nous. En outre, EVAL a également des problèmes pratiques: la portée de la portée, le débogage est désordonné et peut également réduire les performances. Par conséquent, si vous souhaitez charger un script nommé fonctionnalité.js, nous devons utiliser un code comme celui qui suit:
La copie de code est la suivante:
var head = document.getElementsByTagName ('head') [0];
var script = document.createElement ('script');
script.src = 'fonctionnalités.js';
head.appendChild (script);
Bien sûr, nous devons faire face à l'écoute de rappel et la spécification HTML5 définit une propriété Onload qui peut lier les rappels.
La copie de code est la suivante:
script.onload = function () {
console.log ('script chargé ...');
}
Cependant, les versions IE8 et plus anciennes ne prennent pas en charge Onload, elles prennent en charge OnReadyStateChange. De plus, il y a encore beaucoup de choses étranges à gérer les erreurs. Ici, vous pouvez vous référer à certaines bibliothèques de chargement en milieu scolaire populaires, telles que LabJS, Yepnope, Obligation requise, etc.
Comme suit, je résume moi-même un fichier de chargement simple -
La copie de code est la suivante:
var chargejs = fonction (url, rappel) {
var head = document.getElementsByTagName ('head') [0];
var script = document.createElement ('script');
script.src = url;
script.type = "text / javascript";
head.appendChild (script);
// TAG SCRIPT, il y a un événement OnReadyStateChange sous IE, et il y a un événement Onload sous W3C Standard
// IE9 + prend également en charge le chargement de la norme W3C
var ua = Navigator.UserAgent,
ua_version;
// ie6 / 7/8
if (/ msie ([^;] +) /. test (ua)) {
ua_version = parsefloat (regexp ["1 $"], 10);
if (ua_version <= 8) {
script.onreadystatechange = function () {
if (this.readystate == "chargé") {
callback ();
}
}
} autre {
script.onload = function () {
callback ();
};
}
} autre {
script.onload = function () {
callback ();
};
}
};
Je ne parlerai pas du chargement asynchrone des scripts dans document.write. Maintenant, peu de gens le font parce que les différences de navigateur sont vraiment écrasantes.
Notez que l'utilisation de l'objet Image pour précharger les fichiers JS de manière asynchrone, le code JS à l'intérieur ne sera pas exécuté.
Enfin, parlons du script de chargement asynchrone dans requirejs.
requirejs ne garantit pas que les scripts cibles soient exécutés séquentiellement, mais garantit seulement que leur ordre de fonctionnement peut répondre à leurs exigences de dépendance respectives. Par conséquent, nous nous assurons que tous les scripts sont chargés en parallèle dès que possible et les exécutant de manière ordonnée en fonction de la topologie de dépendance.
4. Résumé
OK, en ce qui concerne cela, l'instruction du script de chargement asynchrone est terminée. Permettez-moi de parler à nouveau de l'ordre d'optimisation ici -
1> De la manière traditionnelle, nous utilisons des balises de script pour les intégrer directement dans des documents HTML. Voici deux situations -
A> intégrer dans la balise de tête - faites attention à ce que cela n'aide pas le chargement parallèle d'autres fichiers de ressources statiques dans le contenu du document. Il affecte le rendu du contenu du document, c'est-à-dire que le rendu DOM pour le moment sera bloqué et l'écran blanc sera présenté.
B> intégrer au bas de la balise corporelle - afin d'éviter le phénomène d'écran blanc, nous donnons la priorité pour rendre le DOM puis exécuter le script, mais le problème revient. Parlons d'abord de la première question - si le contenu du document DOM est relativement important, la liaison des événements d'interaction sera retardée et que l'expérience sera un peu pire. Bien sûr, nous devons faire en sorte que les scripts importants s'exécutent d'abord en fonction des besoins. Parlons du deuxième problème - parce que les fichiers de script sont en bas du bas du corps, le chargement de ces scripts est retardé par rapport aux scripts de la tête. Par conséquent, comme au bas du corps, ce n'est pas le point final d'optimisation.
C> Ajouter un attribut Defer - Nous espérons que le script sera chargé en parallèle dès que possible, et nous mettrons toujours ce lot de scripts dans la tête. Le chargement du script doit être effectué simultanément avec le chargement du document et n'affecte pas le rendu du DOM. De cette façon, le script peut être exécuté une fois le document prêt. Il y a donc un attribut de différence. Mais faites attention à sa compatibilité. Pour les navigateurs qui ne prennent pas en charge l'attribut de différence, nous devons encapsuler le code dans un $ (document). Il convient de noter que tous les scripts avec des attributs de report sont exécutés en séquence en fonction de leur ordre d'apparence, il est donc également strictement synchronisé.
2> Le point précédent concerne les scripts d'exécution synchrones (notez que le processus de chargement de ces scripts est parallèle, mais la différence entre qui déclenche d'abord la demande et qui déclenche ensuite la demande). Le point d'optimisation suivant est "Scripts d'exécution parallèle". Bien sûr, nous savons qu'à un moment donné, un seul fichier JS est exécuté. Le "parallèle" signifie ici que celui qui se charge d'abord, tant que le moteur JS est inactif à ce moment, il sera exécuté immédiatement. L'optimisation ici est divisée en deux types -
A> Ajout de la propriété asynchrone - il peut en effet compléter le point d'optimisation que nous avons mentionné ci-dessus, mais il a des limitations élevées, c'est-à-dire qu'elle est uniquement pour le chargement de script de non-dépendance. L'exemple le plus approprié est d'introduire plusieurs scripts tiers. De plus, la combinaison avec l'attribut Deffer est vraiment un gros problème. Bien sûr, il a également des problèmes de compatibilité. Les trois problèmes ci-dessus ont conduit à leur application peu fréquente. Lorsque vous utilisez Async, vous devez prêter une attention particulière aux problèmes de dépendance.
B> Script de chargement de script - Évidemment, nous l'utilisons pour atteindre le but de "l'exécution parallèle des scripts". Dans le même temps, nous facilitons également le contrôle des dépendances de script, nous utilisons donc la gestion de la charge intelligente pour le chargement asynchrone dans requirejs.
Ok, c'est tout.
Ici, je parle juste du contenu lié aux scripts de chargement asynchrones. Il existe une autre partie du contenu, qui est un chargement asynchrone de fichiers de style ou d'autres ressources statiques. à suivre......