我有一个Express.js网络应用程序正在为我的某个域提供服务。 app.js
文件如下所示:
var express = require('express');
var app = express();
// and so on…
我想在app.js
文件中使用我自己的一个函数,所以我想我将函数放在一个单独的文件中(作为一个模块,即module.exports =
个东西)然后在app.js
文件中要求它:
var myfunc = require('./path/to/myfunc');
然而,我担心表现。在Express.js应用程序中需要文件时是否会有明显的性能损失?我想这个问题归结为执行app.js
代码的次数 - 每次我的域的HTTP请求一次或初始化期间只执行一次,以及是否在HTTP请求之间以某种方式缓存require()
结果
答案 0 :(得分:7)
代码require
被提取并执行一次。之后,您将返回module.exports
或exports
中的所有内容。
每当第二次呼叫require
请求位于同一位置的内容时,它都会获得与module.exports
或exports
相同的引用。
在您的特定情况下,代码require
d在引导应用程序时require
d一次,同时引导。
然后,每当请求require
还没有require
时,它就被获取并执行。在此之后的每一次,require
次调用都只会获取缓存的数据。
还记得节点是如何单线程的吗?这就是为什么如果你尝试require
一个不存在的文件,你就会把整个过程都搞砸了。
回答Šime的问题,关于“何时”require
来电被执行。
require
调用在执行代码时会被执行,没有预处理或任何花哨的魔法。如果请求的一部分可以访问该范围,则整个过程将有效地“共享”所有不属于请求的内容。
让我们看一个例子。假设这是你的app.js
,为了简洁,我忽略了所有不相关的快速引导代码。
var a = require('./foo.js'); // [1]
app.get('/thing', function (req, res, next) {
next(); // [2]
});
app.get('/thing', function (req, res, next) {
res.end();
});
app.get('/foo', function (req, res, next) {
res.end(a); // [3]
});
立即获取 [1] foo
,foo
require
,module.exports
被a
分配给express
。
[2]当调用此回调时,我们只是告诉a
,什么也不做,跳过我并转到下一个中间件。
[3]假设module.exports
在foo
内为/foo
分配了一些字符串,则对express
的请求完全可以访问。
您需要考虑的是这些函数只是回调next
保持引用,并在它到达特定的一个时调用它们。它们按顺序处理,直到您调用next
,它会进入下一个中间件。如果您不致电{{1}},则应该结束回复。
我不确定你认为生命周期是如何运作的,但它可能不会像你想象的那样发挥作用。节点只是坐在那里等待请求进来,然后一次处理一个,它永远不会停止,它从来没有真正“重新加载”任何东西。
答案 1 :(得分:3)
来自docs:
模块在第一次加载后进行缓存。这意味着(除其他外)每次调用require('foo')将获得完全相同的返回对象,如果它将解析为同一个文件。
第一次加载后,require
调用中唯一的额外开销是解析文件的路径。通常,对require
的所有调用都放在文件的顶部。