2016-02-26 91 views
13

我想存储在调用链中所有堆栈帧(自上而下)之间共享的变量。很像Java或C#中的ThreadLocal。是否有可能在Node中有“线程”局部变量?

我发现https://github.com/othiym23/node-continuation-local-storage但它保留了所有我的用例的上下文,看起来你必须修补你正在使用的库,使它成为本地存储感知的,这对我们的代码库来说或多或少是不可能的。

Node中是否真的没有其他选项可用?可以使用域,堆栈跟踪或类似的东西来获取当前调用链的句柄(id)。如果这是可能的,我可以写我自己的线程本地实现。

+1

在此问题中添加一个[MCVE]将是一件非常有用的事情。 JS是单线程的,你声明的所有变量在技术上都是线程本地的(或更少)。 – Tomalak

+0

请查看线程局部变量如何在Java,C#甚至Python中工作。这是一个非常成熟的领域,与将普通变量放在堆栈上无关。 https://en.wikipedia.org/wiki/Thread-local_storage – Joppe

+1

我知道线程本地存储是什么。我在说你应该添加一个代码示例来演示你的问题。 – Tomalak

回答

12

是的,这是可能的。 Thomas Watson在NodeConf奥斯陆2016上发表了他的演讲Instrumenting Node.js in Production

它使用Node.js tracing - AsyncWrap(它最终应该成为公共节点API的一部分)。你可以在开源的Opbeat Node agent或者甚至更好的check out the talk slides and example code中看到一个例子。

+0

非常好!谢谢您的帮助。 – Joppe

+0

@Joppe你是怎么做到的? continuation-local-storage似乎现在正在使用这种技术,因为它依赖于谈话中提到的async-listener模块,这些模块目前使用asyncWrap工具。 – Andy

+0

@Andy我真的放弃了这一点,因为我最初收到的所有答案都没有回答真正的问题,而是告诉我要传递一个上下文对象(以新颖的巧妙方式进行编辑)。自从Jakub做出这个发布以来,并没有对此进行研究,但是如果continuation-local-storage将底层技术改变为更可靠的东西,这听起来很有希望。也许是时候再试一次了。 – Joppe

0

TLS用于一些普通的单线程程序使用全局变量的地方,但在多线程情况下这样做不合适。

由于JavaScript没有外露螺纹,全局变量是简单回答你的问题,但使用一个是不好的做法。

您应该改为使用闭包:只需将所有异步调用包装到函数中并在其中定义变量即可。

功能和回调封闭内创建封闭之外创建

(function() (
     var visibleToAll=0; 

     functionWithCallback(params, function(err,result) { 
      visibleToAll++; 
      // ... 
      anotherFunctionWithCallback(params, function(err,result) { 
      visibleToAll++ 
      // ... 
      }); 
     }); 

     functionReturningPromise(params).then(function(result) { 
      visibleToAll++; 
      // ... 
     }).then(function(result) { 
      visibleToAll++; 
      // ... 
     }); 
    ))(); 

功能

若您需要您的变量是请求范围内没有定义可见里面的功能,你可以创建一个上下文对象,而不是和它传递给函数:

(function c() (
     var ctx = { visibleToAll: 0 }; 

     functionWithCallback(params, ctx, function(err,result) { 
      ctx.visibleToAll++; 
      // ... 
      anotherFunctionWithCallback(params, ctx, function(err,result) { 
      ctx.visibleToAll++ 
      // ... 
      }); 
     }); 

     functionReturningPromise(params,ctx).then(function(result) { 
      ctx.visibleToAll++; 
      // ... 
     }).then(function(result) { 
      ctx.visibleToAll++; 
      // ... 
     }); 
    ))(); 

使用上面所有的函数方法称为内c()请参考相同的ctx对象,但对c()的不同调用具有各自的上下文。在典型的用例中,c()将是您的请求处理程序。

结合上下文this

则可以将上下文对象this通过调用它们通过Function.prototype.call绑定在调用的函数:

functionWithCallback.call(ctx, ...) 

...与Function.prototype.bind创建新的功能实例:

var boundFunctionWithCallback = functionWithCallback.bind(ctx) 

...或使用承诺效用函数,如bluebird's .bind

Promise.bind(ctx, functionReturningPromise(data)).then(...) 

任何这些将使CTX提供自己的函数中的this

this.visibleToAll ++; 

...然而它并没有真正的优势,通过传递上下文 - 你的函数仍然需要知道通过this传递的上下文,并且你可能会意外地污染全局对象,如果你曾经没有上下文调用函数。

+0

请看看http://stackoverflow.com/questions/34556637/access-request-context-anywhere。他基本上试图解决和我一样的用例。 您能否说明如何将基于闭包的解决方案应用于此问题(即,不必将请求对象传递给调用链中的每个方法)? – Joppe

+0

这不允许'functionWithCallback'(以及任何未在IIFE中定义的其他函数)访问'visibleToAll'。 – robertklep

+0

不,这是为什么实际上有类似于ES中的线程局部变量的用例的原因之一。 – Joppe

相关问题