2015-03-10 6 views
41

Als ich antwortete another question Ich stieß auf ein Node.js-Modul mit einer Top-Level-return-Anweisung. Zum Beispiel:Warum funktioniert eine Rückgabeanweisung auf Modulebene in Node.js?

console.log("Trying to reach"); 
return; 
console.log("dead code"); 

Dies funktioniert without any errors und Druck:

Trying to reach 

in der Standardausgabe, aber nicht "dead code" - die return tatsächlich aufgehört Ausführung.

Aber nach der specification of return statements in ECMAScript 5.1,

Semantics

Ein ECMAScript Programm syntaktisch falsch angesehen wird, wenn es eine return-Anweisung, die nicht innerhalb eines FunctionBody ist enthält.

In dem oben gezeigten Programm return ist nicht in irgendeiner Funktion.

Dann warum wirft das nicht?

Antwort

82

TL; DR

Die Module werden von Node.js innerhalb einer Funktion, wie diese eingewickelt:

(function (exports, require, module, __filename, __dirname) { 
    // our actual module code 
}); 

wird von Node.js tatsächlich ausgeführt also die oben angezeigten Code ein, wie diese

(function (exports, require, module, __filename, __dirname) { 
    console.log("Trying to reach"); 
    return; 
    console.log("dead code"); 
}); 

Deshalb ist das Programm druckt nur Trying to reach und überspringt die console.log Folge in der return Anweisung.

Internals

Dies ist, wo wir verstehen müssen, wie Node.js Module verarbeitet. Wenn Sie Ihre .js-Datei mit Node.js ausführen, behandelt sie dies als ein Modul und kompiliert es mit der v8-JavaScript-Engine.

Es beginnt alles mit runMain function,

// bootstrap main module. 
Module.runMain = function() { 
    // Load the main module--the command line argument. 
    Module._load(process.argv[1], null, true); 
    // Handle any nextTicks added in the first tick of the program 
    process._tickCallback(); 
}; 

In der Module._load Funktion, ein new Module object is created und it is loaded.

var module = new Module(filename, parent); 
... 
... 
try { 
    module.load(filename); 
    hadException = false; 

Die Module function's load does this,

// Given a file name, pass it to the proper extension handler. 
Module.prototype.load = function(filename) { 
    debug('load ' + JSON.stringify(filename) + 
     ' for module ' + JSON.stringify(this.id)); 

    assert(!this.loaded); 
    this.filename = filename; 
    this.paths = Module._nodeModulePaths(path.dirname(filename)); 

    var extension = path.extname(filename) || '.js'; 
    if (!Module._extensions[extension]) extension = '.js'; 
    Module._extensions[extension](this, filename); 
    this.loaded = true; 
}; 

Da Erweiterung unserer Datei ist js, wir sehen, was die Module._extensions für .js hat.Es kann here

// Native extension for .js 
Module._extensions['.js'] = function(module, filename) { 
    var content = fs.readFileSync(filename, 'utf8'); 
    module._compile(stripBOM(content), filename); 
}; 

Die module_compile Objekt zu sehen ist, in dieser Funktion aufgerufen und this is where the magic happens,

// 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. 

Hier wird die require Funktion, durch unsere Knotenmodule des verwendeten erstellt wird.

function require(path) { 
    return self.require(path); 
} 

require.resolve = function(request) { 
    return Module._resolveFilename(request, self); 
}; 

Object.defineProperty(require, 'paths', { get: function() { 
    throw new Error('require.paths is removed. Use ' + 
        'node_modules folders, or the NODE_PATH ' + 
        'environment variable instead.'); 
}}); 

require.main = process.mainModule; 

// Enable support to add extra extension types 
require.extensions = Module._extensions; 
require.registerExtension = function() { 
    throw new Error('require.registerExtension() removed. Use ' + 
        'require.extensions instead.'); 
}; 

require.cache = Module._cache; 

Und dann gibt es etwas über den Code Einwickeln,

// create wrapper function 
var wrapper = Module.wrap(content); 

Wir setzen, um herauszufinden, was Module.wrap tut, which is nothing but

Module.wrap = NativeModule.wrap; 

which is defined in src/node.js file und das ist, wo wir diese finden ,

NativeModule.wrap = function(script) { 
    return NativeModule.wrapper[0] + script + NativeModule.wrapper[1]; 
}; 

NativeModule.wrapper = [ 
    '(function (exports, require, module, __filename, __dirname) { ', 
    '\n});' 
]; 
Diese

ist, wie unsere Programme Zugang zu den magischen Variablen, exports, require, module, __filename und __dirname

Dann wird die eingewickelt Funktion kompiliert und ausgeführt here mit runInThisContext,

var compiledWrapper = runInThisContext(wrapper, { filename: filename }); 

Und Schließlich wird das kompilierte umbrochene Funktionsobjekt des Moduls wie this aufgerufen, wobei die Werte für exports, 0123, aufgefüllt werden, module, __filename und __dirname

var args = [self.exports, require, self, filename, dirname]; 
return compiledWrapper.apply(self.exports, args); 

Dies ist, wie unsere Module verarbeitet werden und durch Node.js ausgeführt und deshalb ist die return Anweisung ohne Fehler funktioniert.

Verwandte Themen