gpt4 book ai didi

node.js - 模块中的 Node js 全局变量

转载 作者:搜寻专家 更新时间:2023-10-31 23:28:48 24 4
gpt4 key购买 nike

在 Node 中,我看到模块内部全局初始化的变量在请求之间混淆了[一个请求所做的更改会影响另一个请求]。例如:

a.js

var a;
function printName(req, res) {
//get param `name` from url;
a = name;
res.end('Hi '+a);
}
module.exports.printName = printName;

index.js

//Assume all createServer stuffs are done and following function as a CB to createServer
function requestListener(req, res) {
var a = require('a');
a.printName(req, res);
}

根据我的假设,每次新请求到达 Node 时都会执行从模块“a”导出的 printName 函数,并且每次都会有不同的范围对象。

因此,在模块中拥有一些全局的东西不会跨请求影响它们。

但我发现情况并非如此。谁能解释 Node 如何以特定的方式处理函数的模块导出[它处理缓存模块导出对象范围的方式],以及如何克服模块内跨请求共享的全局变量?

编辑[我们根据请求执行异步任务]:在我们的实时系统中有快速请求。基本上查询 redis 并响应请求。我们看到错误的响应映射到错误的请求(redis 查找的回复 [存储在模块中的全局变量中] 错误地映射到 diff req)。而且我们还有一些默认值作为全局变量,可以根据请求参数覆盖它们。这也搞砸了

最佳答案

了解正在发生的事情的第一步是了解幕后发生的事情。从语言的角度来看, Node 模块没有什么特别之处。 “魔法”来自 Node 如何在您require 时从磁盘加载文件。

当您调用require 时, Node 会从磁盘同步读取或返回模块的缓存导出对象。读取文件时,遵循a set of somewhat complex rules要准确确定哪个文件被读取,但是一旦它有一个路径:

  1. 检查 require.cache[moduleName] 是否存在。如果是,返回并停止。
  2. code = fs.readFileSync(path)
  3. Wrap (连接)code 与字符串 (function (exports, require, module, __filename, __dirname) { ... });<
  4. eval 您的包装代码并调用匿名包装函数。

    var module = { exports: {} };
    eval(code)(module.exports, require, module, path, pathMinusFilename);
  5. module.exports 保存为 require.cache[moduleName]

下次您需要同一个模块时, Node 只返回缓存的exports对象。 (这是一件非常好的事情,因为初始加载过程是缓慢且同步的。)

所以现在你应该能够看到:

  • 模块中的顶层代码只执行一次。
  • 因为它实际上是在匿名函数中执行的:
    • “全局”变量实际上不是全局的(除非您明确分配给 global 或不使用 var 限定变量的范围)
    • 这就是模块获取本地范围的方式。

在您的示例中,您需要每个请求的模块a但您实际上在所有请求之间共享相同的模块范围,因为上面概述的模块缓存机制。对 printName 的每次调用在其范围链中共享相同的 a(即使 printName 本身在每次调用时都会获得一个新的范围)。

现在在您的问题中的文字代码中,这并不重要:您设置 a 然后在下一行使用它。控制永远不会离开 printName,因此共享 a 的事实是无关紧要的。我猜你的真实代码看起来更像:

var a;
function printName(req, res) {
//get param `name` from url;
a = name;
getSomethingFromRedis(function(result) {
res.end('Hi '+a);
});
}
module.exports.printName = printName;

这里我们遇到了一个问题,因为控件确实离开了printName。回调最终会触发,但同时另一个请求更改了 a

你可能想要更像这样的东西:

a.js

module.exports = function A() {
var a;
function printName(req, res) {
//get param `name` from url;
a = name;
res.end('Hi '+a);
}

return {
printName: printName
};
}

index.js

var A = require('a');
function requestListener(req, res) {
var a = A();
a.printName(req, res);
}

这样,您就可以在 A 中为每个请求获得一个全新且独立的范围。

关于node.js - 模块中的 Node js 全局变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16396250/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com