我想存储一个在调用链中所有堆栈帧(自上而下)之间共享的变量。与Java或C#中的ThreadLocal非常相似。
我找到了https://github.com/othiym23/node-continuation-local-storage但是它一直在为我的所有用例丢失上下文,似乎你必须修补你正在使用的库以使其本地存储感知,这对我们来说或多或少是不可能的。代码库。
Node中确实没有其他可用选项吗?可以使用域,堆栈跟踪或类似的东西来获取当前调用链的句柄(id)。如果可以的话,我可以编写自己的线程本地实现。
答案 0 :(得分:13)
是的,有可能。 Thomas Watson在他的Instrumenting Node.js in Production
中在2016年奥斯陆NodeConf上发表了演讲它使用Node.js tracing - AsyncWrap(最终应该成为公共Node API中公认的部分)。您可以在开源Opbeat Node agent中看到一个示例,或者甚至更好的check out the talk slides and example code。
答案 1 :(得分:4)
自从我最初提出这个问题已经过去一年多了,最终看起来我们在Node.js 8中以Async Hooks的形式提供了一个有效的解决方案。
https://nodejs.org/api/async_hooks.html
API仍然是实验性的,但即便如此,看起来已经有一个Continuation-Local-Storage的分支在内部使用这个新的API。
答案 2 :(得分: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
传递的上下文,你可能会意外地污染全局对象永远不用上下文调用函数。