Header Ads Widget

Ticker

6/recent/ticker-posts

¿Cómo procesa NodeJs los módulos?

 Todos sabemos que para ejecutar una aplicación de nodo, tenemos que escribir el comando. En esta publicación, veremos cómo NodeJS procesa los módulos.

donde app.jsisel punto de entrada a nuestra aplicación.

Pero rara vez nos preguntamos qué sucede cuando escribimos este comando. ¿Cómo llega mágicamente el nodo a tomar nuestro archivo js y ejecutarlo? Esto es exactamente lo que discutiremos en este artículo.

En otro artículo, describí  cómo nodejs pasa el archivo js al motor V8  y lo convierte en un lenguaje comprensible para el procesador. Aquí hay una trampa. El nodo no envía el contenido del módulo de entrada (app.js) directamente a V8. Primero, procesa este código y lo aumenta envolviéndolo dentro de una función contenedora como se muestra a continuación.

1
2
3
(function (exports, require, module, __filename, __dirname) {
    // content of app.js
});

Después de envolver el código, Node lo pasa a través del motor V8 para compilarlo en código m / c. Entonces, ¿cómo logra eso node? ¿Cuáles son los pasos necesarios para lograrlo? Hablemos de esto en detalle.

Comienza con la   función runMain , que es el módulo principal de arranque (análogo a la función main () de C ++) para el nodo (esta no es la primera función que se ejecuta en realidad. La pila de llamadas va como listOnTimeout -> tryOnTimeout -> ontimeOut -> Module.runMain…. ). Cuando escribimos  node app.js, el entorno del nodo ejecuta este módulo principal.

1
2
3
4
5
...
...
Module._load(process.argv[1], null, true);
...
...

Aquí process.argv[1]corresponde a la cadena "app.js"Entonces, básicamente, el nodo está siendo instruido en _loadel archivoapp.js.

En la   función Module._load ,  se crea un nuevo objeto Module  y luego este módulo se pasa a tryModuleLoadfunctioncargar.

1
2
3
var module = new Module(filename, parent);
...
tryModuleLoad(module, filename);

tryModuleLoad  carga el módulo.

1
2
3
...
module.load(filename)
...

La carga de la función del módulo  realiza una  verificación  de la extensión. Si no se especifica ninguna extensión, la extensión predeterminada es .js

1
2
3
4
...
var extension = findLongestRegisteredExtension(filename);
Module._extensions[extension](this, filename);
...

Dado que nuestra extensión de archivo es .jsModule._extension['.js']se llamará.

1
2
var content = fs.readFileSync(filename, 'utf8');
module._compile(stripBOM(content), filename);

En  esta función sucede lo siguiente.

1
2
3
// Run the file contents in the correct scope or sandbox. Expose
// the correct helper variables (require, module, exports) to the file.
// Returns exception, if any.

Cada módulo tiene exportsrequiremodule__filename__dirnamethisse le atribuye. thisviene según el estándar EcmaScript. Aquí  es donde se declaran estas propiedades para este módulo.

1
2
3
4
5
6
var dirname = path.dirname(filename);
var require = makeRequireFunction(this);
var result;
var exports = this.exports;
var thisValue = exports;
var module = this;

Y luego hay  algo  sobre envolver el código,

1
const wrapper = Module.wrap(content);

Nos dispusimos a averiguar qué hace Module.wrap, que   no es más que

1
2
3
4
5
6
7
let wrap = function(script) {
  return Module.wrapper[0] + script + Module.wrapper[1];
};
const wrapper = [
  '(function (exports, require, module, __filename, __dirname) { ',
  '\n});'
];

Esta es la forma en nuestros programas tienen acceso a las variables de magia ;exports;requiremodule__filename, y__dirname

Ahora podemos ver cómo tenemos nuestra función envuelta de la que hablamos inicialmente.

Luego, esta función envuelta se compila y ejecuta aquí  con finedrunInThisContextde en  vm.jsmodule

01
02
03
04
05
06
07
08
09
10
compiledWrapper = vm.runInThisContext(wrapper, {
      filename,
      lineOffset: 0,
      displayErrors: true,
      importModuleDynamically: experimentalModules ? async (specifier) => {
        if (asyncESM === undefined) lazyLoadESM();
        const loader = await asyncESM.loaderPromise;
        return loader.import(specifier, normalizeReferrerURL(filename));
      } : undefined,
});

Entonces, finalmente, compilado objeto función envuelta del módulo se invoca como  este , con valores de población para las exportaciones, requieren, módulo, __filename y __dirname

1
result = compiledWrapper.call(thisValue, exports, require, module, filename, dirname);

Este valor finalmente se  devuelve

1
return result;

Espero que esto le haya proporcionado una comprensión profunda del nodo y los procesos que ocurren bajo el ciclo.

¡Seguir aprendiendo!

Publicar un comentario

0 Comentarios