为什么模块级别的return语句在Node.js中有效? [英] Why does a module level return statement work in Node.js?

查看:202
本文介绍了为什么模块级别的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.

但根据 ECMAScript 5.1中返回语句的规范

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.

一切都以 runMain 功能

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();
};

Module._load 功能,创建了新的模块对象已加载

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;

src / node.js 文件中定义,这就是我们发现的地方,

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

然后编译并执行包装函数在其中 runInThisContext

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

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

最后,模块的编译包装函数对象被调用,如这个,填充的值为 exports require module __ filename __ dirname

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中有效?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆