是否要求在节点中使用eval在另一个文件中运行代码

时间:2018-09-16 04:54:11

标签: javascript node.js

我只是想了解节点中的模块。我了解到诸如node围绕每个文件中放置的代码创建模块包装器函数之类的事情。

假设有两个文件,即a.js和b.js

在a.js中,当我第一次需要b.js时,如何执行b.js中存在的模块包装函数。

节点是否执行类似的操作,将b.js文件的全部内容作为字符串获取,然后使用eval从a.js执行,然后将该函数调用的结果保存在缓存中。

2 个答案:

答案 0 :(得分:2)

或多或少。

Node.js loads脚本文件内容和wrapsmodule wrapper

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

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

然后模块功能为evaluatedvm.runInThisContext

  var wrapper = Module.wrap(content);

  var compiledWrapper = vm.runInThisContext(wrapper, {
    filename: filename,
    lineOffset: 0,
    displayErrors: true
  });

vm模块提供了V8 execution context,并且vm.runInThisContext与间接eval类似地评估代码:

  

vm.runInThisContext()编译代码,在当前全局变量的上下文中运行它并返回结果。正在运行的代码无权访问本地范围,但有权访问当前的全局对象。

     

<...>

     

由于vm.runInThisContext()无法访问本地范围,因此localVar保持不变。相反,eval()确实可以访问本地范围,因此更改了localVar值。这样vm.runInThisContext()非常类似于间接eval()调用,例如(0,eval)(“代码”)。

答案 1 :(得分:1)

当您确实需要时,node.js具有负责加载模块的loader.js文件。以下步骤由loader.js文件执行

  1. 首先,它检查缓存模块中是否存在该模块。通过 Module._cache
  2. 完成检查
  3. 如果不在缓存中,则创建一个新的Module实例。
  4. 保存到缓存
  5. 使用给定的文件名调用module.load()。 读取文件内容后,将调用module.compile()。
  6. 如果解析文件时出错(因为任何编译器都进行编译,则需要进行词法分析和解析),然后从缓存中删除该模块
  7. 然后返回module.export对象。

我们知道node是开源的,我直接给了node.js的loader.js的github路径

Path of loader.js

这是Node.js团队编写的Module._load函数的代码

// Check the cache for the requested file.
// 1. If a module already exists in the cache: return its exports object.
// 2. If the module is native: call `NativeModule.require()` with the
//    filename and return the result.
// 3. Otherwise, create a new module for the file and save it to the cache.
//    Then have it load  the file contents before returning its exports
//    object.
Module._load = function(request, parent, isMain) {
  if (parent) {
    debug('Module._load REQUEST %s parent: %s', request, parent.id);
  }

  var filename = Module._resolveFilename(request, parent, isMain);

  var cachedModule = Module._cache[filename];
  if (cachedModule) {
    updateChildren(parent, cachedModule, true);
    return cachedModule.exports;
  }

  if (NativeModule.nonInternalExists(filename)) {
    debug('load native module %s', request);
    return NativeModule.require(filename);
  }

  // Don't call updateChildren(), Module constructor already does.
  var module = new Module(filename, parent);

  if (isMain) {
    process.mainModule = module;
    module.id = '.';
  }

  Module._cache[filename] = module;

  tryModuleLoad(module, filename);

  return module.exports;
};

也请查看本文以了解流程的工作原理

How require() Actually Works