本文介绍了为什么模块级别的return语句在Node.js中有效?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我回答时,我遇到了一个顶级<$ c $的Node.js模块c> return 声明。例如:

When I was answering another question I came across a Node.js module with a top-level return statement. For example:

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

这可行和打印:

Trying to reach

标准输出中的

但不是死代码 - return 实际上已停止执行。

in the standard output but not "dead code" - the return actually ceased execution.

但根据,

But according to the specification of return statements in ECMAScript 5.1,

如果ECMAScript程序包含一个返回语句,则认为它在语法上是不正确的不在 FunctionBody

An ECMAScript program is considered syntactically incorrect if it contains a return statement that is not within a FunctionBody.

在显示的程序中以上返回不在任何函数范围内。

In the program shown above return is not within any function.

那为什么不扔?

推荐答案

TL; DR

模块由函数中的Node.js包装,如下所示:

The modules are wrapped by Node.js within a function, like this:

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

所以上面显示的代码实际上是由Node.js执行的,就像这样

So the above shown code is actually executed by Node.js, like this

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

这就是为什么程序只打印试图达到并在 return 语句后跳过 console.log

That is why the program prints only Trying to reach and skips the console.log following the return statement.

这是我们需要了解Node.js如何处理模块的地方。当您使用Node.js运行.js文件时,它会将其视为模块并使用v8 JavaScript引擎进行编译。

This is where we need to understand how Node.js processes Modules. When you run your .js file with Node.js, it treats that as a module and compiles it with the v8 JavaScript engine.

一切都以,

It all starts with 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();
};

在功能,和。

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

The 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;
};

由于我们的文件扩展名是 js ,我们看看 Module._extensions 对于 .js 的含义。可以看到

Since our file's extension is js, we see what the Module._extensions has for .js. It can be seen here

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

模块对象的 _compile 在该函数中被调用并且,

The module object's _compile is invoked in that function and 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.

这是功能,首先创建我们的节点模块。

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;

然后有一些关于包装代码的事情,

And then there is something about wrapping the code,

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

我们开始寻找 Module.wrap 确实,

Module.wrap = NativeModule.wrap;

,这就是我们发现的地方,

which is defined in src/node.js file and that is where we find this,

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

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

这是我们的程序可以访问魔术变量的方式, exports require module __ filename __ dirname

This is how our programs have access to the magic variables, exports, require, module, __filename and __dirname

然后编译并执行包装函数 ,

Then the wrapped function is compiled and executed here with runInThisContext,

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

最后,模块的编译包装函数对象被调用,如,填充的值为,,,和

And then finally, the module's compiled wrapped function object is invoked like this, with values populated for exports, require, module, __filename and __dirname

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

这是我们的模块由Node.js处理和执行的方式,这就是为什么 return 语句可以正常工作。

This is how our modules are processed and executed by Node.js and that is why the return statement works without failing.

这篇关于为什么模块级别的return语句在Node.js中有效?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-19 02:40
查看更多