La carga del módulo en realidad divide JS en muchos módulos para un fácil desarrollo y mantenimiento. Por lo tanto, al cargar muchos módulos JS, es necesario cargar dinámicamente para mejorar la experiencia del usuario.
Antes de introducir la biblioteca de carga del módulo, presentaremos un método.
Carga dinámica del método JS:
La copia del código es la siguiente:
función loadjs (url, devolución de llamada) {
var nodo = document.createElement ("script");
nodo [window.addeventListener? "Onload": "OnreadyStateChange"] = function () {
if (window.adDeventListener || /Loaded|Complete/i.test(node.readyState)) {
llamar de vuelta();
node.onreadyStateChange = null;
}
}
node.onerror = function () {};
node.src = url;
var head = document.getElementsByTagName ("Head") [0];
head.insertbefore (nodo, head.firstchild); // Antes de insertarlo en el primer nodo de la cabeza, evite que la etiqueta del cabezal debajo de IE6 esté cerrada y use AppendChild para informar un error.
}
Dado que Situ Zhengmei usó el marco masivo que escribió para introducir la carga del módulo, el más utilizado en la industria es requerir.js y mar.js. Por lo tanto, creo que tiene una personalidad fuerte.
Permítanme hablar sobre el proceso de carga del mar.js:
La página Chaosan.js se introduce en la etiqueta de cabeza, y se obtendrá el objeto SEAJS.
También introduzca index.js.
El código de index.js es el siguiente:
La copia del código es la siguiente:
Seajs.use (['./ a', 'jQuery'], function (a, $) {
var num = aa;
$ ('#J_a'). Text (num);
})
A.JS:
La copia del código es la siguiente:
Definir (función (requerir, exportar, módulo) {
var b = require ('./ b');
var a = function () {
return 1 + parseint (bb ());
}
exports.a = a;
})
B.JS:
La copia del código es la siguiente:
Definir (función (requerir, exportar, módulo) {
var c = require ('./ c');
var b = function () {
return 2 + parseint (cc ());
}
exports.b = b;
})
C.JS:
La copia del código es la siguiente:
Definir (función (requerir, exportar, módulo) {
var c = function () {
regresar 3;
}
exports.c = c;
})
De lo anterior, podemos ver que el módulo A depende de B, y B depende de c.
Cuando el programa ingresa index.js, SEAJS llamará al método de uso.
La copia del código es la siguiente:
Seajs.use = function (ids, devolución de llamada) {
GlobalModule._use (IDS, devolución de llamada)
}
Descripción: Cuando GlobalModule se inicializa en SEAJS (cuando se introduce SEA.JS), la instancia del módulo var globalModule = new Module (util.Pageuri, status.compiled)
En este momento IDS -> ['./a','jquery'], Callback -> function (a, $) {var num = aa; $ ('#j_a'). Text (num);}
A continuación, se llamará a GlobalModule._use (IDS, devolución de llamada)
La copia del código es la siguiente:
Módulo.prototype._use = function (ids, llamado) {
var uris = resolve (ids, this.uri); // Resolución ['./a','jquery']
this._load (uris, function () {// llame a la dirección del módulo A y jQuery analizado [URL1, URL2] y llame al método _load.
//util.map: deje que todos los miembros de datos ejecuten la función especificada a la vez y devuelvan una nueva matriz, que es el resultado de la ejecución de devolución de llamada del miembro de la matriz original
var args = util.map (uris, function (uri) {
¿Volver a Uri? CachedModules [uri] ._ compile (): null; // Si la url existe, llame al método _compile.
})
if (callback) {callback.apply (null, args)}
})
}
Porque después de llamar al método _load, aparecerán dos funciones de devolución de llamada, por lo que marcamos la función (a, $) {var num = aa; $ ('#j_a'). Text (num);} para llamar a la devoción1,
Establezca esto._load (Uris, function () {}) El indicador de método de devolución de llamada en Callback2.
El método de resolución es resolver la dirección del módulo, para que no entraré en detalles aquí.
Finalmente, el URI en var uris = resolve (ids, this.uri) se analizó en ['http: //localhost/test/seajs/a.js','http: //localhost/test/seajs/lib/juqery/1.7.2/juqery-debug.js', y el modulo se ha completado.
Y luego esto.
La copia del código es la siguiente:
// El método _load () primero determinará qué archivos de recursos aún no están listos. Si todos los archivos de recursos están en el estado listo, Callback2 se ejecutará.
// En este caso, también haremos dependencias circulares y realizaremos la carga de JS descargado
Módulo.prototype._load = function (uris, callback2) {
//util.filter: deje que todos los miembros de datos ejecuten la función especificada a la vez y devuelvan una nueva matriz. La matriz es un miembro que devuelve verdadero después de ejecutar una devolución de llamada del miembro original de la matriz.
// DescargedUris es una matriz de módulos que no se compilan
var descarateedure = util.filter (uris, function (uri) {
// Devuelve un miembro cuya función de ejecución el valor booleano es verdadero, devuelve verdadero cuando el URI existe y no existe en los Cachemódulos variables internos o almacena el valor del estado menor que el estado. Listo en la información de almacenamiento
// Si el valor de estado.
Devuelve Uri && (! CachedModules [uri] ||
Cachedmodules [uri] .status <status.ready)
});
// Si todos los módulos en URI están listos, ejecute la devolución de llamada y salga del cuerpo de la función (esta vez se llamará al método _compile del módulo).
Var longitud = DescargedUris.length
if (longitud === 0) {callback2 () return}
// el número de módulos no cargados
VAR queda = longitud
// crear cierres e intentar cargar módulos que no están cargados
para (var i = 0; i <longitud; i ++) {
(función (uri) {
// juzga si la información de almacenamiento de URI no existe en la variable interna Cachedmodules, instanciar un objeto de módulo
módulo var = CachedModules [URI] ||
(CachedModules [URI] = nuevo módulo (uri, status. -fetching))
// Si el valor de estado del módulo es mayor o igual a 2, significa que el módulo ha sido descargado y ya existe localmente. En este momento, Onfetched () se ejecuta
// de lo contrario, Fetch (URI, Onfetched) se llama para intentar descargar el archivo de recursos. Onload se activará después de descargar el archivo de recursos, y el método Onfetched se ejecutará en el Onload.
módulo.status> = status.fetched? Onfetched (): Fetch (Uri, Onfetched)
función onfetched () {
módulo = CachedModules [URI]
// Cuando el valor de estado del módulo es mayor o igual al estado.
if (módulo.status> = status.saved) {
// GetPuredPendencies: obtenga una matriz de dependencia sin dependencias circulares
var deps = getPuredEpendencies (módulo)
// Si la matriz de dependencia no está vacía
if (deps.length) {
// Ejecutar el método _load () nuevamente hasta que todas las dependencias estén cargadas y la devolución de llamada se ejecute después de que se complete la carga de todas las dependencias
Módulo.prototype._load (deps, function () {
CB (módulo)
})
}
// Si la matriz de dependencia está vacía, ejecute CB (módulo) directamente
demás {
CB (módulo)
}
}
// Si la adquisición falla, como 404 o no cumple con la especificación modular
// En este caso, el módulo.status se mantendrá en busca o obtenida
demás {
CB ()
}
}
}) (DescargedUris [i])
}
// Método CB: ejecute la devolución de llamada después de cargar todos los módulos
función CB (módulo) {
// Si existe la información de almacenamiento del módulo, luego modifique el valor de estado en su información de almacenamiento del módulo y modifíquela al estado.
módulo && (módulo.status = status.ready)
// Las devoluciones de llamada se ejecutan solo cuando se cargan todos los módulos.
--Remain === 0 && Callback2 ()
}
}
}
Aquí, la longitud de la matriz de Descareduris es 2, ['http: //localhost/test/seaJs/a.js','http: //localhost/test/seajs/lib/juqery/1.7.2/juqery-debug.js'], así que dos cierres con el nombre de la ruta de Js se generarán a continuación.
Tome http: //localhost/test/seajs/a.js como ejemplo
Siguiente: Primero, se creará un módulo:
La copia del código es la siguiente:
CachedModules ('http: //localhost/test/seajs/a.js') = nuevo módulo ('http: //localhost/test/seajs/a.js',1)
módulo.status> = status.fetched? Onfetched (): Fetch (Uri, Onfetched)
Debido a que el módulo A no está cargado en este momento, Fetch (Uri, Onfetched) se ejecutará a continuación, es decir, Fetch ('http: //localhost/test/seajs/a.js', no fethed).
La copia del código es la siguiente:
function fetch (uri, onfetched) {
// Reemplazar URI con la nueva dirección de solicitud de acuerdo con las reglas del mapa
var requestUri = util.ParsEmap (URI)
// Primero, averigüe si el registro de requesturi está contenido en la lista obtenida
if (fetchedList [requestUri]) {
// En este momento, actualice la información de almacenamiento del módulo del URI original al requesturi redefinido por mapa
Cachedmodules [URI] = CachedModules [requesturi]
// ejecutar onfetched y return, lo que significa que el módulo se ha obtenido con éxito
Onfetched ()
Devolver
}
// Consulta la información de almacenamiento de Solicitude en la lista Obtener
if (fetchingList [requestUri]) {
// Agregar la devolución de llamada correspondiente al URI en la lista de devolución de llamada y regresar
CallbackList [requesturi] .push (onfetched) // Si se está recuperando, presione el método de devolución de llamada en este módulo en la matriz y devuélvalo.
Devolver
}
// Si los módulos que está intentando obtener no aparecen en FetchedList y FetchingList, agregue su información en la lista de solicitudes y la lista de devolución de llamada respectivamente
FetchingList [requestUri] = True
callbackList [requestUri] = [Onfetched]
// lo busca
Módulo._fetch (
requesturi,
función() {
FetchedList [requestUri] = True
// Actualiza el estado del módulo
// if module.status es igual al estado.
módulo var = CachedModules [URI]
if (module.status === status.fetching) {
módulo.status = status.fetched
}
if (fetchingList [requestUri]) {
Eliminar FetchingList [requesturi]
}
// llama a la ejecución de devoluciones de llamada unificadas
if (CallbackList [requestUri]) {
Util.ForEach (CallbackList [requestUri], function (fn) {
fn () // fn es el método ONFeChed correspondiente al módulo a.
})
Eliminar CallbackList [requesturi]
}
},
config.charset
)
}
A continuación, se ejecutará módulo._fetch (), y llamamos a la función de devolución de llamada aquí como Callback3.
Este método es llamar al método LoadJS para descargar dinámicamente el archivo A.JS. (Debido a que hay A y jQuery, se crearán dos nuevos scripts). Hay una pregunta aquí. Si crea un script para A y agrega al cabezal, descargará el archivo JS. Sin embargo, en SEAJS, no se descarga. En su lugar, esperará hasta que se establezca el script para jQuery y se agregue a la cabeza antes de descargarlo (Google Debugger establece un punto de interrupción, y sigue mostrando pendiente en espera). ¿Es esto para Mao?
(Recomendado aquí: http://ux.sohu.com/topics/50972d9ae7de3e752e0081ff. Hablaré sobre preguntas adicionales aquí. Puede saber por qué necesitamos usar las tablas para diseñar menos, porque cuando la tabla se representa, debe ser que el adivinte solo sea el adivino, mientras que el adivino solo lo necesita. Antes de que se muestre, y el DIV se mostrará tanto como se analiza.
Después de que la descarga sea exitosa, se analizará y ejecutará, y se ejecuta el método Define. Aquí ejecutaremos primero el código del módulo a.
Define (id, deps, function () {}) análisis del método
La copia del código es la siguiente:
// Definir definición, ID: ID del módulo, DEPS: Dependencia del módulo, fábrica
Módulo._define = function (id, deps, fábrica) {
// Resolver dependencias // Si Deps no es un tipo de matriz, la fábrica es una función
if (! util.isArray (deps) && util.isfunction (fábrica))) {// El cuerpo de la función coincide regularmente con la cadena requerir y forma una matriz para devolver la asignación a DEPS
DEPS = Util.ParsedEpendences (factory.toString ())
}
// establecer meta información
var meta = {id: id, dependencias: deps, fábrica: fábrica}
if (document.attachevent) {
// Obtener el nodo del script actual
var script = util.getCurrentScript ()
// Si el nodo de script existe
if (script) {
// Obtener la dirección URI original
derivedUri = util.unparsEmap (util.getScriptAbSolutesRC (script))}
if (! deriveduri) {
Util.log ('no pudo obtener URI del script interactivo para:', factory.toString (), 'advertir')
}
}
.........
}
Definir primero realizará un juicio sobre la fábrica para determinar si es una función (la razón es que la definición también puede incluir archivos y objetos)
Si se trata de una función, la función se obtendrá a través de factory.toString (), y la dependencia de A.JS coincide regularmente, y la dependencia se guardará en DEPS
Para A.JS, su dependencia es B.JS, por lo que Deps es ['./B']
Y guarde la información de a.js var meta = {id: id, dependencias: deps, fábrica: fábrica}
Para A.JS meta = {id: Undefined, Dependencies: ['./b'], fábrica: function (xxx) {xxx}}
En el navegador IE 6-9, puedes obtener el camino para ejecutar JS. Sin embargo, en un navegador estándar, esto no es factible, por lo que puede asignar la meta información a AnonymousModulemeta = meta.
Luego active OnLoad y se llamará al método de devolución de llamada de devolución de llamada3. Este método de devolución de llamada modificará el valor de estado del módulo de devolución de llamada actual (A.JS) y lo establecerá en módulo.status = status.fetched.
A continuación, la devolución de llamada correspondiente a A.JS en el Llamback BackbackList de la cola de devolución de llamada se ejecutará de manera uniforme, es decir, Onfetched.
El método Onfetched verifica si un módulo A tiene un módulo dependiente. Debido a que A depende de B, ejecute _load () en B.js en el que depende el módulo A.
El módulo B se descargará y el método de definición jQuery se ejecutará primero. Porque JQuery no depende de los módulos, después de la devolución de llamada en Onload. Onfetched llamadas CB Método.
Cuando B se implementa en el mismo proceso que A, se descargará el Módulo C. Finalmente, el C, B, A los módulos se descargan y ejecutan, y después de completar la carga, el método CB también se llamará (primero C, luego B, luego C)
Después de que todos los módulos estén listos, se llamará al método Callback2.
Finalmente, la devolución de llamada se llama Back2 y se ejecuta el método _compile de los módulos A y JQuery:
Primero, compile el módulo A.JS y ejecute la función del módulo a. Debido a que A ha requerido (b.js) en él, ejecutará la función del módulo b.
La función del módulo A comienza la ejecución
La función del módulo B comienza a ejecutarse
La función del módulo C inicia la ejecución
La ejecución de la función del módulo C se ha completado
La ejecución de la función del módulo B se ha completado
La ejecución de la función del módulo A se ha completado
Finalmente, ejecute la función de jQuery.
Después de la compilación, ejecute CallBack1 y puede usar objetos A y JQuery.
PD: La versión SEAJS se ha actualizado y ahora no hay un método _compile. (Todos van a verlo usted mismo, yo también quiero verlo)
Hablemos sobre el proceso de compilación del módulo SeAJS_Compile.
Primero, la compilación de A.JS
La copia del código es la siguiente:
Módulo.prototype._compile = function () {
126 módulo var = esto
127 // Si se ha compilado el módulo, entonces return Module.Exports directamente
128 if (module.status === status.compiled) {
129 módulo de retorno.exports
130}
133 // 1. El archivo del módulo es 404.
134 // 2. El archivo del módulo no está escrito con formato de módulo válido.
135 // 3. Otros casos de error.
136 // Aquí hay algunas excepciones para tratar, y luego devolver a NULL directamente
137 if (module.status <status.saved &&! Hasmodifiers (módulo)) {
138 regresa nulo
139}
140 // Cambiar el estado del módulo a compilar, lo que significa que el módulo se está compilando
141 módulo.status = status.com Popiling
142
143 // El uso interno del módulo es un método utilizado para obtener la interfaz proporcionada por otros módulos (llamados submódulos) y operar sincrónicamente
144 FUNCIÓN DESECHA (ID) {
145 // ruta la ruta del módulo según ID
146 var uri = resolve (id, module.uri)
147 // Obtener módulos de la memoria caché del módulo (tenga en cuenta que las dependencias del submódulo como módulo principal se han descargado)
148 var niño = cacheedmodules [uri]
149
150 // Solo regresa nulo cuando URI no es válido.
151 // Si el niño está vacío, solo puede significar que el parámetro se llena incorrectamente y luego devuelve nulo directamente
152 if (! Child) {
153 regreso nulo
154}
155
156 // Evita las llamadas circulares.
157 // Si el estado del submódulo es el estado.
158 if (child.status === status.compiling) {
159 devuelve child.exports
160}
161 // señala el módulo que llama al módulo actual durante la inicialización. Según esta propiedad, puede obtener la pila de llamadas cuando se inicializa el módulo.
162 Child.Parent = Módulo
163 // Devuelve el módulo. Exports del niño compilado
164 return child._compile ()
165}
166 // Usado internamente para cargar el módulo de forma asincrónica y ejecutar la devolución de llamada especificada después de completar la carga.
167 require.async = function (ids, devolución de llamada) {
168 módulo._use (IDS, devolución de llamada)
169}
170 // Use el mecanismo de resolución de ruta dentro del sistema del módulo para analizar y devolver la ruta del módulo. Esta función no carga el módulo y solo devuelve la ruta absoluta analizada.
171 require.resolve = function (id) {
172 Return Resolve (id, módulo.uri)
173}
174 // A través de esta propiedad, puede ver todos los módulos cargados por el sistema del módulo.
175 // En algunos casos, si necesita volver a cargar un módulo, puede obtener el URI del módulo y luego eliminar su información por Eliminar requerir.cache [URI]. Esto se volverá a acumular la próxima vez que lo use.
176 require.cache = CachedModules
177
178 // Requerir es un método para obtener interfaces proporcionadas por otros módulos.
179 módulo.require = requerir
180 // exportaciones es un objeto que proporciona interfaces de módulo al exterior.
181 módulo.exports = {}
182 var factory = módulo.factory
183
184 // Cuando la fábrica es una función, representa el constructor del módulo. Al ejecutar este método, puede obtener la interfaz proporcionada por el módulo al exterior.
185 if (util.Isfunction (fábrica)) {
186 compilestack.push (módulo)
187 runinModuleContext (fábrica, módulo)
188 compilestack.pop ()
189}
190 // Cuando la fábrica es un tipo de no función, como un objeto, una cadena, etc., la interfaz que representa el módulo es el objeto, una cadena y otros valores.
191 // Por ejemplo: Define ({"foo": "bar"});
192 // Por ejemplo: Define ('Soy una plantilla. Mi nombre es {{nombre}}.');
193 más if (fábrica! == Undefined) {
194 módulo.exports = fábrica
195}
196
197 // Cambiar el estado del módulo a compilado, lo que significa que el módulo ha sido compilado
198 módulo.status = status.compiled
199 // Ejecutar la modificación de la interfaz del módulo, a través de SEAJS.Modify ()
200 execmodificadores (módulo)
201 módulo de retorno. Exports
202}
La copia del código es la siguiente:
if (Util.Isfunct (fábrica)) {
186 compilestack.push (módulo)
187 runinModuleContext (fábrica, módulo)
188 compilestack.pop ()
189}
Aquí está la inicialización de Module.Export. Método RunInModuleContext:
La copia del código es la siguiente:
// Ejecutar el código del módulo de acuerdo con el contexto del módulo
Función 489 runinModuleContext (fn, módulo) {
490 // Pase en dos parámetros relacionados con el módulo y el módulo mismo
491 // Las exportaciones se utilizan para exponer interfaces
492 // requerir que se use para obtener módulos dependientes (sincrónicos) (compilar)
493 var retir = fn (módulo.require, module.exports, módulo)
494 // admite la forma de la interfaz de exposición al valor de retorno, como:
495 // return {
496 // fn1: xx
497 //, fn2: xx
498 // ...
499 //}
500 if (ret! == indefinido) {
501 módulo.exports = RET
502}
503}
Ejecutar el método de función en A.JS, y luego se llamará a VAR B = requirir ("b.js"),
El método Requerir devolverá el valor de retorno del método de compilación de B, y hay var c = requirir ('c.js') en el módulo B.
En este momento, se llamará al método de compilación de C, y luego se llamará a la función de C. En C, si el objeto se expone o se devuelve el objeto de retorno C, las exportaciones del módulo C serán exportaciones = c. O directamente módulo.export = c; En resumen, el módulo c.export = c se devolverá al final; entonces var c = módulo c.export = c. En el módulo B, puede usar la variable C para llamar a los métodos y propiedades del objeto C en el módulo c.
Por analogía, el módulo A puede eventualmente llamar a las propiedades y métodos del objeto B en el módulo b.
No importa qué módulo, siempre que use Module.Export = XX Module, otros módulos pueden usar requerir ("módulo xx") para llamar a varios métodos en el módulo xx.
El estado del módulo final se convertirá en módulo.status = status.compiled.
La copia del código es la siguiente:
Módulo.prototype._use = function (ids, llamado) {
var uris = resolve (ids, this.uri); // Resolución ['./a','jquery']
this._load (uris, function () {// llame a la dirección del módulo A y jQuery analizado [URL1, URL2] y llame al método _load.
//util.map: deje que todos los miembros de datos ejecuten la función especificada a la vez y devuelvan una nueva matriz, que es el resultado de la ejecución de devolución de llamada del miembro de la matriz original
var args = util.map (uris, function (uri) {
¿Volver a Uri? CachedModules [uri] ._ compile (): null; // Si la url existe, llame al método _compile.
})
if (callback) {callback.apply (null, args)}
})
}
En este momento args = [módulo a.export, módulo jquery.export];
La copia del código es la siguiente:
Seajs.use (['./ a', 'jQuery'], function (a, $) {
var num = aa;
$ ('#J_a'). Text (num);
})
En este momento, A y $ en la función son el módulo A.Export y el módulo jQuery.export.
Debido a que ahora estoy estudiando el código fuente de jQuery y el diseño de JQuery Framework, comparto algo de experiencia:
Código fuente de jQuery, he leído mucho análisis en línea, pero no puedo leerlo más mientras lo miro. No es muy significativo, por lo que recomiendo el análisis del código de código de fuente JQuery de Miaowei.
El diseño del marco JavaScript de Situ Zhengmei es difícil, pero después de una lectura cuidadosa, se convertirá en un ingeniero de front-end senior.
Sugiero aprender y usar el mar de Yu Bo, después de todo, está hecho por los propios chinos. Los nuevos proyectos o reconstrucciones de nuestra empresa se realizarán utilizando SEAJS.
El siguiente es el código fuente de lectura intensiva de barras pesadas modulares y columna vertebral MVC o MVVM Angular. Aquí espero que alguien me dé sugerencias sobre qué libros, sitios web y videos para aprender rápidamente.