当前位置:  开发笔记 > 编程语言 > 正文

节点js模块中的全局变量

如何解决《节点js模块中的全局变量》经验,为你挑选了1个好方法。

在节点I中,看到变量初始化模块内部的变量正在混淆[一个请求完成的更改影响另一个请求].对于Ex:

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

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

因此,在模块中使用全局内容不会影响它们的请求.

但我发现事实并非如此.任何人都可以解释节点如何处理特定的函数模块导出[它处理缓存模块导出对象的范围的方式]以及如何跨模块中的请求克服这个共享的全局变量?

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



1> josh3736..:

了解正在发生的事情的第一步是了解幕后发生的事情.从语言的角度来看,节点模块并没有什么特别之处."魔力"来自于节点如何从磁盘加载文件require.

当您调用时require,node可以同步从磁盘读取或返回模块的缓存导出对象.在读取文件时,它遵循一组有些复杂的规则来确定读取哪个文件,但是一旦它有一个路径:

    检查是否require.cache[moduleName]存在.如果是,请返回并停止.

    code = fs.readFileSync(path).

    code用字符串换行(连接)(function (exports, require, module, __filename, __dirname) {...});

    eval 你的包装代码并调用匿名包装函数.

    var module = { exports: {} };
    eval(code)(module.exports, require, module, path, pathMinusFilename);
    

    另存module.exportsrequire.cache[moduleName].

下次require使用同一模块时,节点只返回缓存的exports对象.(这是一件非常好的事情,因为初始加载过程缓慢且同步.)

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

模块中的顶级代码仅执行一次.

因为它实际上是在匿名函数中执行的:

"全局"变量实际上并不是全局变量(除非您明确指定global或不使用变量作用域var)

这是模块获取本地范围的方式.

在您的示例中,您为每个请求require模块化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以为每个请求获得一个全新且独立的范围.

推荐阅读
kikokikolove
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有