Le chargement du module divise en fait JS en de nombreux modules pour un développement et une maintenance faciles. Par conséquent, lors du chargement de nombreux modules JS, il est nécessaire de charger dynamiquement pour améliorer l'expérience utilisateur.
Avant d'introduire la bibliothèque de chargement du module, nous présenterons une méthode.
Charge dynamique de la méthode JS:
La copie de code est la suivante:
Fonction Loadjs (URL, rappel) {
var node = document.createElement ("script");
node [window.addeventListener? "onload": "onreadystatechange"] = fonction () {
if (window.addeventListener || /loaded|complete/i.test(node.readystate)) {
callback ();
node.onreadystateChange = null;
}
}
node.onerror = function () {};
Node.src = url;
var head = document.getElementsByTagName ("Head") [0];
head.insertbefore (nœud, head.firstchild); // Avant de l'insérer dans le premier nœud de la tête, empêchez la balise de tête sous IE6 d'être fermée et utilisez une annexe pour signaler une erreur.
}
Étant donné que la situation Zhengmei a utilisé le cadre de masse qu'il a écrit pour introduire le chargement des modules, le plus utilisé dans l'industrie est nécessaire.js et sea.js. Par conséquent, je pense qu'il a une forte personnalité.
Permettez-moi de parler du processus de chargement de Sea.js:
La page Chaosan.js est introduite dans l'étiquette de tête et l'objet SeaJS sera obtenu.
Introduire également index.js.
Le code d'index.js est le suivant:
La copie de code est la suivante:
Seajs.use (['./ a', 'jQuery'], fonction (a, $) {
var num = aa;
$ ('# J_a'). Text (num);
})
A.JS:
La copie de code est la suivante:
définir (fonction (require, exportations, module) {
var b = require ('./ b');
var a = fonction () {
retour 1 + parseInt (bb ());
}
export.a = a;
})
B.JS:
La copie de code est la suivante:
définir (fonction (require, exportations, module) {
var c = require ('./ c');
var b = fonction () {
retour 2 + parseInt (cc ());
}
export.b = b;
})
C.JS:
La copie de code est la suivante:
définir (fonction (require, exportations, module) {
var c = fonction () {
retour 3;
}
exports.c = c;
})
À partir de ce qui précède, nous pouvons voir que le module A dépend de B, et B dépend de c.
Lorsque le programme entre sur index.js, Seajs appellera la méthode d'utilisation.
La copie de code est la suivante:
SeaJs.use = fonction (ids, rappel) {
GlobalModule._use (IDS, rappel)
}
Description: Lorsque GlobalModule est initialisé dans SEAJS (lorsque Sea.js est introduit), l'instance du module var globalmodule = nouveau module (util.pageuri, status.compilé)
À ce moment ids -> ['./a' ,'jquery'], rappel -> function (a, $) {var num = aa; $ ('# j_a'). Text (num);}
Ensuite, GlobalModule._Use (ids, rappel) sera appelé
La copie de code est la suivante:
Module.prototype._use = fonction (ids, rappel) {
var uris = résolution (ids, this.uri); // Résolution ['./a' ,'jquery']
this._load (uris, function () {// Appelez l'adresse du module analysé A et jQuery [URL1, URL2] et appelez la méthode _load.
//util.map: Laissez tous les membres de données exécuter la fonction spécifiée à la fois et renvoyer un nouveau tableau, qui est le résultat de l'exécution de rappel du membre d'origine
var args = util.map (uris, fonction (uri) {
Retour URI? cachedModules [uri] ._ compile (): null; // si l'URL existe, appelez la méthode _Compile.
})
if (callback) {callback.apply (null, args)}
})
}
Parce qu'après avoir appelé la méthode _load, deux fonctions de rappel apparaîtront, nous inscrivons donc la fonction (a, $) {var num = aa; $ ('# j_a'). Text (num);} à callback1,
Définissez This._Load (uris, function () {}) Flag de méthode de callback sur callback2.
La méthode Resolve consiste à résoudre l'adresse du module, donc je n'entrerai pas dans les détails ici.
Enfin, l'uris dans var uris = résolution (ids, this.uri) a été analysé dans ['http: //localhost/test/seajs/a.js' ,'http: //localhost/test/seajs/lib/juqery/1.7.2/juqey-debug.js'], et le module est terminé.
Et ensuite ce._load sera exécuté
La copie de code est la suivante:
// La méthode _load () déterminera d'abord quels fichiers de ressources ne sont pas encore prêts. Si tous les fichiers de ressources sont à l'état prêt, Callback2 sera exécuté.
// Dans ce cas, nous ferons également des dépendances circulaires et effectuerons un chargement sur JS non chargé
Module.prototype._load = fonction (uris, callback2) {
//util.filter: Laissez tous les membres de données exécuter la fonction spécifiée à la fois et renvoyez un nouveau tableau. Le tableau est un membre qui renvoie True après avoir exécuté un rappel à partir du membre du tableau d'origine.
// Unchargeduris est un tableau de modules qui ne sont pas compilés
var un chargedUris = util.filter (uris, function (uri) {
// Renvoie un membre dont la fonction d'exécution de la fonction booléenne est vraie, renvoie vrai lorsque l'URI existe et n'existe pas dans la variable interne cachemodules ou qu'il stocke la valeur du statut inférieure au statut.
// Si la valeur de statut est 4, si elle est inférieure à quatre, il est possible qu'il soit récupéré et téléchargé.
return uri && (! cachedModules [uri] ||
cachedModules [uri] .status <statut.ready)
});
// Si tous les modules d'Uris sont prêts, exécutez le rappel et sortez du corps de fonction (cette fois, la méthode _Compile du module sera appelée).
var longueur = un chargedUris.length
if (longueur === 0) {callback2 () return}
// le nombre de modules non chargés
var restes = longueur
// Créez des fermetures et essayez de charger des modules qui ne sont pas chargés
pour (var i = 0; i <longueur; i ++) {
(fonction (uri) {
// Jugez si les informations de stockage URI n'existent pas dans la variable interne CachedModules, instanciez un objet de module
Var Module = CachedModules [URI] ||
(CachedModules [URI] = nouveau module (URI, status.fetching))
// Si la valeur d'état du module est supérieure ou égale à 2, cela signifie que le module a été téléchargé et existe déjà localement. À l'heure
// Sinon, Fetch (URI, OnFetchred) est appelé pour essayer de télécharger le fichier de ressources. Onload sera déclenché après le téléchargement du fichier de ressources et la méthode onfettée sera exécutée dans le chargement.
module.status> = status.fet etd? onfetched (): fetch (uri, onfetfed)
Fonction OnFetched () {
module = cachedModules [URI]
// Lorsque la valeur d'état du module est supérieure ou égale à l'état.
if (module.status> = status.saved) {
// GetPuredEstences: Obtenez un tableau de dépendance sans dépendances circulaires
var Deps = GetPuredEstences (module)
// Si le tableau de dépendance n'est pas vide
if (depS.Length) {
// Exécuter à nouveau la méthode _load () jusqu'à ce que toutes les dépendances soient chargées et que le rappel soit exécuté une fois le chargement de toutes les dépendances
Module.prototype._load (deps, function () {
CB (module)
})
}
// Si le tableau de dépendance est vide, exécutez directement CB (module)
autre {
CB (module)
}
}
// Si l'acquisition échoue, comme 404 ou ne respecte pas la spécification modulaire
// Dans ce cas, le module.status sera maintenu à la récupération ou récupéré
autre {
CB ()
}
}
}) (un chargedUris [i])
}
// Méthode CB - Exécutez un rappel après le chargement de tous les modules
fonction cb (module) {
// Si les informations de stockage du module existent, modifiez la valeur d'état dans ses informations de stockage de module et modifiez-la à Status.ready
module && (module.status = status.ready)
// Les rappels sont exécutés uniquement lorsque tous les modules sont chargés.
--remain === 0 && callback2 ()
}
}
}
Ici, la longueur du tableau de Unchargeduris est de 2, ['http: //localhost/test/seajs/a.js' ,'http: //localhost/test/seajs/lib/juqery/1.7.2/juqery-debug.js'], donc deux fermetures avec le nom du piste js qui sera générée.
Prendre http: //localhost/test/seajs/a.js comme exemple
Suivant: Tout d'abord, un module sera créé:
La copie de code est la suivante:
cachedmodules ('http: //localhost/test/seajs/a.js') = nouveau module ('http: //localhost/test/seajs/a.js',1)
module.status> = status.fet etd? onfetched (): fetch (uri, onfetfed)
Étant donné que le module A n'est pas chargé pour le moment, Fetch (URI, onfet ett) sera exécuté ensuite, c'est-à-dire fetch ('http: //localhost/test/seajs/a.js',onfetched).
La copie de code est la suivante:
fonction fetch (uri, onfet etd) {
// Remplacez URI par la nouvelle adresse de demande en fonction des règles de la carte
var demandeUri = util.parsemap (uri)
// Tout d'abord, découvrez si le dossier de demande est contenu dans la liste obtenue
if (fetchedList [requeturi]) {
// À l'heure
cachedModules [uri] = cachedModules [requeturi]
// Exécuter sur le plan et le retour, ce qui signifie que le module a été obtenu avec succès
onfetched ()
Retour
}
// Informations de stockage de demande de demande de demande dans la liste d'obtention
if (fetchingList [requeturi]) {
// Ajouter le rappel correspondant à l'URI dans la liste de rappel et retourner
callbacklist [requestUri] .push (onfet ett) // s'il est récupéré, poussez la méthode de rappel onfettée de ce module dans le tableau et renvoyez-le.
Retour
}
// Si les modules que vous essayez d'obtenir n'apparaissent pas dans FetchDedList et FetchingList, ajoutez leurs informations dans la liste des demandes et la liste de rappel respectivement
fetchingList [requestUri] = true
callbacklist [requestUri] = [onfetched]
// le récupére
Module._fetch (
requeturi,
fonction() {
FetchDedList [requeturi] = true
// met à jour l'état du module
// si module.status est égal à status.fectching, modifiez l'état du module à récupérer
module var = cachedModules [URI]
if (module.status === status.fetching) {
module.status = status.
}
if (fetchingList [requeturi]) {
supprimer fetchinglist [requestUri]
}
// appelle l'exécution unifiée des rappels unifiés
if (callbacklist [requestUri]) {
util.ForEach (callbacklist [requestUri], fonction (fn) {
fn () // fn est la méthode onfechée correspondant au module a.
})
supprimer callbacklist [requestUri]
}
},
config.Charset
)
}
Ensuite, module._fetch () sera exécuté et nous appelons la fonction de rappel ici comme callback3.
Cette méthode consiste à appeler la méthode LoadJS pour télécharger dynamiquement le fichier A.JS. (Parce qu'il y a un et jQuery, deux nouveaux scripts seront créés). Il y a une question ici. Si vous créez un script pour A et l'ajoutez à la tête, vous téléchargerez le fichier JS. Cependant, dans Seajs, il n'est pas téléchargé. Au lieu de cela, vous attendez que le script de jQuery soit établi et ajouté à la tête avant de le télécharger (Google Debugger définit un point d'arrêt, et il continue de montrer l'attente en attente). Est-ce pour Mao?
(Recommandé ici: http://ux.sohu.com/topics/50972d9ae7de3e752e0081ff. Je parlerai de questions supplémentaires ici. Avant qu'il ne soit affiché, et le div sera affiché autant qu'il est analysé après la vérification, s'il y a une balise TBOD dans le tableau, il sera affiché dans les segments en fonction de TBOD.
Une fois le téléchargement réussi, il sera analysé et exécuté, et la méthode Define sera exécutée. Ici, nous allons d'abord exécuter le code du module a.
Définir (id, DEPS, fonction () {}) Analyse de la méthode
La copie de code est la suivante:
// Définition de définition, ID: ID du module, DEPS: dépendance du module, usine
Module._define = fonction (id, deps, usine) {
// résoudre les dépendances // Si les DEP ne sont pas un type de tableau, l'usine est une fonction
if (! util.isArray (deps) && util.isfunction (usine)) {// Le corps de fonction correspond régulièrement à la chaîne requise et forme un tableau pour renvoyer l'affectation à Deps
DEPS = util.parsedependces (factory.toString ())
}
// Définir les méta-informations
var meta = {id: id, dépendances: DEPS, usine: usine}
if (document.attachevent) {
// Obtenez le nœud du script actuel
var script = util.getCurrentScript ()
// Si le nœud de script existe
if (script) {
// Obtenez l'adresse URI d'origine
Deriveduri = util.unparSemap (util.getscriptAbsolutesrc (script))}
if (! Deriveduri) {
util.log ('Impossible de dériver URI du script interactif pour:', factory.toString (), 'Warn')
}
}
.........
}
Définira d'abord un jugement sur l'usine pour déterminer s'il s'agit d'une fonction (la raison en est que la définition peut également inclure des fichiers et des objets)
S'il s'agit d'une fonction, la fonction sera obtenue via factory.toString (), et la dépendance de A.JS est égalée régulièrement, et la dépendance sera enregistrée dans les DEP
Pour A.JS, sa dépendance est B.JS, donc les DEPS sont ['./b']
Et enregistrer les informations de A.Js var meta = {id: id, dépendances: DEPS, usine: usine}
Pour a.js meta = {id: non défini, dépendances: ['./b'], usine: fonction (xxx) {xxx}}
Dans le navigateur IE 6-9, vous pouvez obtenir le chemin de l'exécution de JS. Cependant, dans un navigateur standard, cela n'est pas possible, vous pouvez donc affecter les informations Meta à AnonymousModuleMeta = META.
Ensuite, déclenchez sur onload et la méthode de rappel Callback3 sera appelée. Cette méthode de rappel modifiera la valeur d'état du module de rappel actuel (A.JS) et le définira sur module.status = status.fet etd.
Ensuite, le rappel correspondant à A.JS dans la liste de rappel de la file d'attente de rappel sera exécuté uniformément, c'est-à-dire sur lefché.
La méthode onfché vérifie si un module A a un module dépendant. Parce que A dépend de B, exécutez _load () sur B.Js sur lequel le module A dépend.
Le module B sera téléchargé et la méthode de définition jQuery sera d'abord exécutée. Parce que jQuery ne dépend pas des modules, après le rappel Onload. CALLS ONFICHED CALS CB.
Lorsque B est implémenté dans le même processus qu'un, le module C sera téléchargé. Enfin, le C, B, un module est téléchargé et exécuté, et une fois le chargement terminé, la méthode CB sera également appelée (d'abord C, puis b, puis c)
Une fois que tous les modules sont prêts, la méthode Callback2 sera appelée.
Enfin, le rappel est appelé Back2 et la méthode _Compile des modules A et JQuery est exécutée:
Tout d'abord, compilez le module A.JS et exécutez la fonction du module a. Parce que A a besoin (b.js), il exécutera la fonction du module b.
La fonction du module A démarre l'exécution
La fonction du module B commence à exécuter
La fonction du module C démarre l'exécution
L'exécution de la fonction du module C a été achevée
L'exécution de la fonction du module B a été achevée
L'exécution de la fonction du module A est terminée
Enfin, exécutez la fonction de jQuery.
Après la compilation, exécutez Callback1 et vous pouvez utiliser A et JQuery Objets.
PS: La version Seajs a été mise à jour, et il n'y a pas de méthode _compile maintenant. (Tout le monde va le voir vous-même, je veux le voir aussi)
Parlons du processus SeaJS Module Compilation_Compile.
Premièrement, la compilation de A.JS
La copie de code est la suivante:
Module.prototype._compile = function () {
126 VAR MODULE = CECI
127 // Si le module a été compilé, retournez le module.Exports directement
128 if (module.status === status.compilé) {
129 Retour Module.Exports
130}
133 // 1. Le fichier du module est 404.
134 // 2. Le fichier du module n'est pas écrit avec le format de module valide.
135 // 3. Autres cas d'erreur.
136 // Voici quelques exceptions à gérer, puis retourner NULL directement
137 if (module.status <status.saved &&! Hasmodificateurs (module)) {
138 retour null
139}
140 // modifie l'état du module en compilation, ce qui signifie que le module est compilé
141 module.status = status.compilt
142
143 // L'utilisation interne du module est une méthode utilisée pour obtenir l'interface fournie par d'autres modules (appelés sous-modules) et fonctionner de manière synchrone
144 Fonction requis (id) {
145 // Chemin du chemin du module selon ID
146 var uri = résolution (id, module.uri)
147 // Obtenez des modules du cache du module (notez que les dépendances du sous-module comme module principal ont été téléchargées)
148 Var Child = CachedModules [URI]
149
150 // retourne simplement nul lorsque URI n'est pas valide.
151 // Si l'enfant est vide, cela peut seulement signifier que le paramètre est rempli de manière incorrecte, puis renvoie Null directement
152 if (! Enfant) {
153 retour null
154}
155
156 // évite les appels circulaires.
157 // Si le statut du sous-module est status.compilt, renvoyez Child.Exports directement pour éviter la compilation répétée des modules dus aux dépendances circulaires.
158 if (child.status === status.compilant) {
159 Return Child.exports
160}
161 // pointez le module qui appelle le module actuel lors de l'initialisation. En fonction de cette propriété, vous pouvez obtenir la pile d'appels lorsque le module est initialisé.
162 child.parent = module
163 // Renvoie le module.Exports de l'enfant compilé
164 return child._compile ()
165}
166 // utilisé en interne pour charger le module de manière asynchrone et exécuter le rappel spécifié une fois le chargement terminé.
167 require.async = fonction (ids, rappel) {
168 module._use (ids, rappel)
169}
170 // Utilisez le mécanisme de résolution du chemin à l'intérieur du système du module pour analyser et retourner le chemin du module. Cette fonction ne charge pas le module et ne renvoie que le chemin absolu analysé.
171 require.resolve = function (id) {
172 Retour Resolve (id, module.uri)
173}
174 // via cette propriété, vous pouvez afficher tous les modules chargés par le système de modules.
175 // Dans certains cas, si vous avez besoin de recharger un module, vous pouvez obtenir l'URI du module, puis supprimer ses informations par supprimer require.cache [uri]. Ceci sera réapprovisionné la prochaine fois que vous l'utiliserez.
176 require.cache = cachedModules
177
178 // exiger est une méthode pour obtenir des interfaces fournies par d'autres modules.
179 module.
180 // Les exportations sont un objet qui fournit des interfaces de module vers l'extérieur.
181 module.exports = {}
182 var usine = module.factory
183
184 // Lorsque l'usine est une fonction, elle représente le constructeur du module. En exécutant cette méthode, vous pouvez obtenir l'interface fournie par le module à l'extérieur.
185 if (util.isfunction (usine)) {
186 compilestack.push (module)
187 RuninmoduleContext (usine, module)
188 compilestack.pop ()
189}
190 // Lorsque l'usine est un type de non-fonction comme un objet, une chaîne, etc., l'interface représentant le module est l'objet, une chaîne et d'autres valeurs.
191 // par exemple: définir ({"foo": "bar"});
192 // par exemple: définir ('je suis un modèle. Mon nom est {{nom}}.');
193 else if (usine! == Undefined) {
194 module.exports = usine
195}
196
197 // Modifier l'état du module à compilé, ce qui signifie que le module a été compilé
198 module.status = status.compilé
199 // Exécuter la modification de l'interface du module, via seajs.modify ()
200 execmodificateurs (module)
201 Retour Module.Exports
202}
La copie de code est la suivante:
if (util.isfunction (usine)) {
186 compilestack.push (module)
187 RuninmoduleContext (usine, module)
188 compilestack.pop ()
189}
Voici l'initialisation de module.export. Méthode RunInModuleContext:
La copie de code est la suivante:
// Exécuter le code du module en fonction du contexte du module
489 fonction runInModuleContext (fn, module) {
490 // passer en deux paramètres liés au module et au module lui-même
491 // Les exportations sont utilisées pour exposer les interfaces
492 // a besoin est utilisé pour obtenir des modules dépendants (synchrones) (compilation)
493 var ret = fn (module.require, module.exports, module)
494 // prend en charge la forme d'interface de l'exposition à la valeur de retour, telles que:
495 // return {
496 // fn1: xx
497 //, fn2: xx
498 // ...
499 //}
500 if (ret! == Undefined) {
501 module.exports = ret
502}
503}
Exécuter la méthode de fonction en A.JS, puis var b = require ("b.js") sera appelé,
La méthode requise renvoie la valeur de retour de la méthode de compilation de b, et il y a var c = require ('c.js') dans le module b.
À l'heure actuelle, la méthode de compilation de C sera appelée, puis la fonction de C sera appelée. En C, si l'objet doit être exposé ou que l'objet de retour C est renvoyé, les exportations du module C seront des exportations = c. Ou directement module.export = c; En bref, le module C.Export = C sera renvoyé à la fin; Donc var c = module C.Export = c. Dans le module B, vous pouvez utiliser la variable C pour appeler les méthodes et les propriétés de l'objet C dans le module c.
Par analogie, le module A peut éventuellement appeler les propriétés et les méthodes de l'objet B dans le module b.
Quel que soit le module, tant que vous utilisez module.export = xx module, d'autres modules peuvent utiliser require ("module xx") pour appeler diverses méthodes dans le module xx.
L'état du module final deviendra module.status = status.compilé.
La copie de code est la suivante:
Module.prototype._use = fonction (ids, rappel) {
var uris = résolution (ids, this.uri); // Résolution ['./a' ,'jquery']
this._load (uris, function () {// Appelez l'adresse du module analysé A et jQuery [URL1, URL2] et appelez la méthode _load.
//util.map: Laissez tous les membres de données exécuter la fonction spécifiée à la fois et renvoyer un nouveau tableau, qui est le résultat de l'exécution de rappel du membre d'origine
var args = util.map (uris, fonction (uri) {
Retour URI? cachedModules [uri] ._ compile (): null; // si l'URL existe, appelez la méthode _Compile.
})
if (callback) {callback.apply (null, args)}
})
}
À l'heure actuelle, args = [module a.export, module jQuery.export];
La copie de code est la suivante:
Seajs.use (['./ a', 'jQuery'], fonction (a, $) {
var num = aa;
$ ('# J_a'). Text (num);
})
À l'heure actuelle, A et $ dans la fonction sont le module a.export et le module jQuery.export.
Parce que j'étudie maintenant le code source jQuery et la conception de framework jQuery, je partage une certaine expérience:
JQUERY CODE SOURCE, j'ai lu beaucoup d'analyses en ligne, mais je ne peux plus le lire en le regardant. Ce n'est pas très significatif, donc je recommande l'analyse du code source jQuery de Miaowei.
La conception du cadre JavaScript de Situ Zhengmei est difficile, mais après une lecture attentive, vous deviendrez un ingénieur frontal senior.
Je suggère d'apprendre et d'utiliser la mer de Yu Bo.js, après tout, il est fait par les Chinois eux-mêmes. Les nouveaux projets ou reconstructions de notre entreprise seront réalisés à l'aide de SEAJS.
Ensuite, la lecture intensive du code source des bancs de mains modulaires et de la squelette MVC ou MVVM Angular. Ici, j'espère que quelqu'un me donnera des suggestions sur les livres, les sites Web et les vidéos à apprendre rapidement.