Casi todos los desarrolladores de Node.js pueden decirle lo que hace la función `necesaria ()`, pero ¿cuántos de nosotros realmente sabemos cómo funciona? Lo usamos todos los días para cargar bibliotecas y módulos, pero su comportamiento es un misterio para nosotros.
Por curiosidad, profundicé en el código central de nodo para averiguar qué sucedió debajo del motor. Pero esta no es una sola función. Encontré módulo.js en el sistema de módulo de nodo. El archivo contiene un módulo de núcleo sorprendentemente potente y relativamente desconocido que controla la carga, la compilación y el almacenamiento en caché de cada archivo. `requerir ()`, su aparición es solo la punta del iceberg.
módulo.js
La copia del código es la siguiente:
módulo de función (id, parent) {
this.id = id;
this.exports = {};
this.parent = parent;
// ...
En Module.js, juega principalmente dos roles dentro de Node.js. Primero, proporciona una base para todos los módulos Node.js. Cada archivo es una nueva instancia del módulo base nuevo, y todavía existe incluso después de que se haya ejecutado el archivo. Es por eso que podemos adjuntar las propiedades a módulo.exports y devolverlas cuando sea necesario.
La segunda tarea principal de este módulo es manejar el mecanismo de carga del módulo del nodo. La operación independiente de la función "Requerir" que utilizamos es en realidad un concepto abstracto. Este método de carga maneja la carga real de cada archivo e inicia nuestro viaje allí.
Módulo.
La copia del código es la siguiente:
Módulo._load = function (solicitud, parent, isMain) {
// 1. Verifique el módulo._cache para el módulo en caché.
// 2. Cree una nueva instancia de módulo si el caché está vacío.
// 3. Guardo en el caché.
// 4. Llame al módulo.load () con su nombre de archivo dado.
// Esto llamará al módulo.compile () después de leer el contenido del archivo.
// 5. Si hubo un error cargar/analizar el archivo,
// Eliminar el módulo malo del caché
// 6. Return module.exports
};
Module._load es responsable de cargar nuevos módulos y administrar cachés de módulos. El caché cargado cada módulo reduce el número de lecturas de archivos redundantes y puede acelerar significativamente su aplicación. Además, la instancia del módulo compartido permite que los módulos con características de singleton permanezcan en el estado en el proyecto.
Si no existe un módulo en el caché, el módulo._load creará un nuevo módulo base para el archivo. Luego le dirá al módulo que lea el contenido del nuevo archivo antes de enviarlos al módulo._compile. [1]
Si nota el paso #6 anterior, verá que Module.Exports ha sido devuelto al usuario. Es por eso que cuando está definiendo el uso de la interfaz pública, utiliza exportaciones y módulo. Me sorprendió que no hubiera más funciones aquí, pero sería mejor si hubiera.
módulo._compile
La copia del código es la siguiente:
Módulo.prototype._compile = function (content, filename) {
// 1. Cree la función independiente requiere una función que llame a módulo.require.
// 2. Adjunte otros métodos auxiliares para requerir.
// 3. Envuelve el código JS en una función que proporciona nuestro requisito,
// módulo, etc. Variables localmente al alcance del módulo.
// 4. Ejecute esa función
};
・ Aquí es donde sucede el verdadero milagro. Primero, se crea una función de requisito operativo especial e independiente para el módulo. Esta es una característica que necesitamos y con la que todos estamos familiarizados. La función en sí es solo una encapsulación en Module.require, que también contiene algunos métodos auxiliares menos conocidos que son fáciles de usar para nosotros:
・ Requerir (): cargar un módulo externo
・ Require.resolve (): analice un nombre de módulo a su camino absoluto
・ Requerir. Mayor: módulo principal
・ Require.cache: todos los módulos almacenados en caché
・ ・ ・ ・ ・ ・ ・ ・ ・ ・ ° de extensiones: un método de compilación que se puede utilizar para cada tipo de archivo válido de acuerdo con su extensión
Una vez que el requerimiento esté listo, todo el código fuente cargado se encapsulará en una nueva función, lo que le permite aceptar requerir, módulo, exportaciones y todas las demás variables expuestas como parámetros. Esta es una función creada solo para encapsular módulos para evitar conflictos con el entorno Node.js.
La copia del código es la siguiente:
(función (exporta, requerir, módulo, __filename, __Dirname) {
// ¡Su código inyectado aquí!
});
El método de módulo._compile se ejecuta sincrónicamente, por lo que la llamada al módulo.
en conclusión
Por lo tanto, ya hemos entendido el código completo de necesidad y tenemos una comprensión preliminar de cómo funciona.
Si lo ha hecho todo el camino, entonces está listo para el último secreto: requerir ('módulo'). Esto es correcto, el sistema del módulo en sí se puede cargar a través del sistema de módulos. Comienzo. Esto puede sonar extraño, pero permite que el espacio del usuario interactúe con los sistemas de carga de módulos sin profundizar en el núcleo Node.js. Los módulos populares están construidos así. [2]
Si desea saber más, consulte el código fuente de módulo.js usted mismo. Todavía hay muchas cosas que serán suficientes para que tenga dolor de cabeza por un tiempo. El primero puede decirme qué es Node_Module_Contexts "y por qué se agrega puede obtener puntos de bonificación :)
[1] El método de módulo._compile solo se usa para ejecutar archivos JavaScript. El archivo json debe analizarse a través de json.parse () y devuelto
[2] Sin embargo, ambos módulos se basan en métodos de módulos privados como el módulo. Puedes pensar que esto no es mucho mejor ...