模块内的Node js全局变量 [英] Node js globals within modules

查看:91
本文介绍了模块内的Node js全局变量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在节点中,我看到模块内部全局初始化的变量变得混在一起[一个请求所做的更改会影响另一个请求]. 例如:

In node I see variables initialized global inside modules are getting mixed up [changes done by one request affects the other] across requests. For 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函数,并且每次都会有不同的作用域对象.

As per my assumption, printName function exported from module 'a' is executed everytime a new request hits node and it will have different scope object everytime.

因此,在模块内部具有全局性不会对请求产生影响.

So, having something global inside a module wouldn't be affecting them across requests.

但是我看到情况并非如此.谁能解释节点如何具体处理功能的模块导出[它如何处理缓存的模块导出对象的范围],以及如何克服模块内各个请求之间的共享全局变量?

But I see that isn't the case. Can anyone explain how does node handle module exports of functions in specific [way it handles the scope of the cached module exports object] and how to overcome this shared global variables across requests within a module?

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

Edit [We do async task per request]: With rapid requests in our live system. Which basically query redis and responds the request. We see wrong response mapped to wrong request (reply [stored in a global var in the module] of a redis look up wrongly mapped to diff req). And also we have some default values as global vars which can be overridden based on request params. Which also is getting screwed up

推荐答案

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

The first step to understanding what is happening is understanding what's happening behind the scenes. From a language standpoint, there's nothing special about node modules. The 'magic' comes from how node loads files from disk when you require.

调用require时,节点要么从磁盘同步读取,要么返回模块的缓存导出对象.读取文件时,它会按照一组有点复杂的规则来确定哪个文件被读取,但是一旦它具有路径:

When you call require, node either synchronously reads from disk or returns the module's cached exports object. When reading files, it follows a set of somewhat complex rules to determine exactly which file is read, but once it has a path:

  1. 检查是否存在require.cache[moduleName].如果是这样,则返回该值并停止.
  2. code = fs.readFileSync(path).
  3. 包装(并置)code字符串(function (exports, require, module, __filename, __dirname) { ... });
  4. eval您的包装代码并调用匿名包装器功能.

  1. Check if require.cache[moduleName] exists. If it does, return that and STOP.
  2. code = fs.readFileSync(path).
  3. Wrap (concatenate) code with the string (function (exports, require, module, __filename, __dirname) { ... });
  4. eval your wrapped code and invoke the anonymous wrapper function.

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

  • module.exports另存为require.cache[moduleName].

  • Save module.exports as require.cache[moduleName].

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

    The next time you require the same module, node simply returns the cached exports object. (This is a very good thing, because the initial loading process is slow and synchronous.)

    所以现在您应该可以看到:

    So now you should be able to see:

    • 模块中的顶级代码仅执行一次.
    • 由于它实际上是在匿名函数中执行的,因此:
      • 全局"变量实际上不是全局变量(除非您显式分配给global或不使用var限制变量的范围)
      • 这是模块获取本地范围的方式.
      • Top-level code in a module is only executed once.
      • Since it is actually executed in an anonymous function:
        • 'Global' variables aren't actually global (unless you explicitly assign to global or don't scope your variables with var)
        • This is how a module gets a local scope.

        在您的示例中,您为每个请求require模块 a ,但是由于模块缓存机制,您实际上在所有需求之间共享相同的模块作用域以上概述.每次对printName的调用在其作用域链中共享相同的a(即使printName本身在每次调用时都会获得一个新的作用域).

        In your example, you require module a for each request, but you're actually sharing the same module scope across all requrests because of the module caching mechanism outlined above. Every call to printName shares the same a in its scope chain (even though printName itself gets a new scope on each invocation).

        现在在您的问题中使用的文字代码中,这没关系:您设置a,然后在下一行使用它.控件永远不会离开printName,因此共享a的事实是无关紧要的.我的猜测是您的真实代码更像是:

        Now in the literal code you have in your question, this doesn't matter: you set a and then use it on the very next line. Control never leaves printName, so the fact that a is shared is irrelevant. My guess is your real code looks more like:

        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.

        Here we have a problem because control does leave printName. The callback eventually fires, but another request changed a in the meantime.

        您可能想要更多类似这样的东西:

        You probably want something more like this:

        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中获得一个全新的独立作用域.

        This way, you get a fresh and independent scope inside of A for each request.

        这篇关于模块内的Node js全局变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆