在node.js中加载和执行外部文件

8

从另一个node js文件运行一个node js文件是否容易/可能?例如,我有两个文件test1.js和test2.js。我想从test2.js执行test1.js文件。


“执行”是什么意思?与在test1.js中执行require('test2.js')有何不同? - adrianp
@adrianp 这样写 "node test1.js" 就可以执行或运行 Node.js 文件了。我想从 test2.js 中运行 test1.js。 - sudhakar
@sudhakar,你是在说类似于这个的东西吗?(http://www.dzone.com/snippets/execute-unix-command-nodejs) - kentcdodds
例如,test1.js的内容如下:if (process.argv.length > 0) { var test_val = process.argv[1]; } console.log(test_val);如果我在命令行中运行它 "node test1.js wow"输出将是wow。因此,我想从test2.js获取输出"wow"。 - sudhakar
你只是想单独运行test1,还是希望test1可以访问test2的变量? - SheetJS
3个回答

15

我认为实现你试图做的事情更好的方法是使用我另一个答案建议的方式。但根据你的问题,如果想要在命令行上执行命令,你需要使用child_process.exec。例如:

var exec = require('child_process').exec,
    child;

child = exec('node test2.js {{args}}',
  function (error, stdout, stderr) {
    console.log('stdout: ' + stdout);
    console.log('stderr: ' + stderr);
    if (error !== null) {
      console.log('exec error: ' + error);
    }
});

12

只需运行require('test2.js'),然后调用导出对象上的函数。根据模块文档

Node拥有简单的模块加载系统。在Node中,文件和模块一一对应。例如,foo.js在相同目录下加载模块circle.js。

foo.js的内容:

var circle = require('./circle.js');
console.log( 'The area of a circle of radius 4 is ' + circle.area(4));

circle.js的内容:

var PI = Math.PI;

exports.area = function (r) {
  return PI * r * r;
};

exports.circumference = function (r) {
  return 2 * PI * r;
};
模块circle.js已导出函数area()和circumference()。 要导出对象,请添加到特殊的exports对象中。
请注意,exports是对module.exports的引用,仅适用于增强。如果要导出单个项目(例如构造函数),则应直接使用module.exports。
function MyConstructor (opts) {
  //...
}

// BROKEN: Does not modify exports
exports = MyConstructor;

// exports the constructor properly
module.exports = MyConstructor;

模块内部的变量将被视为私有变量。在这个例子中,变量 PI 是 circle.js 私有的。

模块系统是在 require("module") 模块中实现的。


2
嗯...不确定为什么这个答案被踩了。即使它不是被接受的答案,这也是与模块交互的正确方式... - kentcdodds
4
如果我将它作为模块,就不能单独运行它。我有一些独立的脚本用于执行某些任务,还有一些调度程序脚本可以按指定顺序运行所有需要的任务。如果我的任务是具有输出的模块,我就不能单独运行这些任务,我必须创建一些包装脚本来运行任务。 - JustAMartin
@J 只需将所有内容包装在一个函数中,然后测试脚本是否作为模块运行:// 允许我们直接运行或通过另一个node.js脚本运行 if (require.main === module) { // 我们正在直接运行 runTest() } else { // 我们是另一个脚本中的模块 module.exports = runTest } - Julian Knight

2
这里有不同的情况 - 使用模块,以“正确的方式”加载它们 - 这是编写自己代码的方法。如果涉及到“随机”的.js文件,例如通过网络爬取下载的文件(是否执行这些文件是另一个问题),那么你可以直接require它们,如果你只对它们的副作用感兴趣。
console.log('hello')

test1.js:

console.log('about to execute')
require('./test2.js')
console.log('done')

请注意require()中的./。但是,如果你想运行两次,这样是行不通的:

test3.js

console.log('about to execute twice?')
require('./test2.js')
require('./test2.js')
console.log('surprise')

这表明,require的工作方式类似于Python中的import——只有在文件没有被加载时才会执行。但是,有可能绕过它并强制重新加载:如何在node.js中在require后删除模块? test4.js:
console.log('about to execute twice!')
require('./test2.js')
delete require.cache[require.resolve('./test2.js')]
require('./test2.js')
console.log('NO surprise this time around')

与 Python 的 import 不同之处在于,除非被导出,否则无法导入任何内容。因此,您需要更改 require 文件并使用 module.exports 进行一些操作。

如果您正在使用 node shell,则有一个替代方法:

test5.js

console.log('the const below is private?')
const x = 5

然后:

$ node
> .load test5.js
console.log('the const below is private?')
const x = 5

the const below is private?
undefined
> x
5

请注意,在.load中没有引号,也没有./。这在使用时会有些冗长(回显已加载的脚本)。但至少这是一种操作脚本创建值的方式。
最后警告:始终小心你要执行的内容!

"./" 做了我想要的事情(与原作者不同)。 我对 node.js 还不是很了解,但我有一种感觉,当您将路径留空时,它会自动默认在 node_modules 中查找模块,然后在全局 node_modules 中查找。 但是,在刚开始学习 node.js 时并不立即清楚。 因此,我很感谢您的回答。 它非常清晰地解决了我的问题。 - Nicholas R. Grant

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接