【问题标题】:How to work around promises when using continuation-local-storage?使用 continuation-local-storage 时如何解决 Promise?
【发布时间】:2019-06-27 20:33:07
【问题描述】:

continuation-local-storage 似乎被使用,也在 express 的上下文中。

但是非常基本的用法对我不起作用,因为上下文完全丢失了!

var createNamespace = require('continuation-local-storage').createNamespace;
var session = createNamespace('my session');


async function doAsync() {
    console.log('Before getting into the promise: ' + session.get('test'));
    await Promise.resolve();
    console.log('*in* the promise: ' + session.get('test'));
}

session.run(() => {
    session.set('test', 'peekaboo');
    doAsync();
});

结果:

$ node server_test.js 
Before getting into the promise: peekaboo
*in* the promise: undefined

是我做错了什么还是 CLS 完全坏了? 还是图书馆坏了? 如果它不适合使用 Promise,是否还有其他概念可以作为 threadLocal 存储以适当的方式实现多租户?

【问题讨论】:

  • 为什么不doAsync("peakaboo")?是的,图书馆似乎没有提到承诺。
  • @JonasWilms 这只是一个简约的例子。该库用于多租户环境,在我的实际用例中,它从 mongo db 获取文档,但我认为这个示例更适合理解问题。
  • JavaScript 本身提供了一种机制来访问不同作业内部的共享状态,闭包。每个试图模仿这种行为的库都会付出巨大的代价,因为它必须与每一项工作挂钩。这就是为什么 NodeJS 不推荐使用它的原生 hooks 库,因为它遇到了同样的问题。这些库没有得到维护表明它们也远非完美。
  • @JonasWilms 你可以扩展闭包如何用于这种情况吗?节点现在做什么?如何从任何地方访问与请求相关的值?

标签: javascript node.js promise continuation-local-storage


【解决方案1】:

cls-hooked 似乎工作正常,尽管该库(如上一个)最近一次更新是在两年前...

如果有人有其他更强大的方法来实现多租户的线程本地状态,请分享!

【讨论】:

  • cls-hooked 似乎是continuation-local-storage 的直接替代品(与我的用例完全相同的API),甚至很难使用setTimeout/setInterval 的回调,甚至promise.then(),那么只有cls-hookedawait promise 被调用后工作
【解决方案2】:

您正试图在多个函数之间保持共享状态,然后这些函数会异步执行。这是 JS 中非常常见的情况,语言本身为此提供了一种非常简单但功能强大的机制:您可以从内部函数访问外部函数中的变量,即使外部函数已经执行完毕:

 (function closured() {
    let shared = { /*...*/ };

    function inner() {
      console.log( shared );
    }
    setTimeout(inner);
  })();

虽然这可行,但它不适用于更大的应用程序:所有访问该状态的函数都必须在一个函数内,因此该文件会被炸毁。您正在使用的库正在尝试解决这个问题,它们还使用闭包来维护异步调用中的状态:当您注册异步回调时,状态存储在函数中,然后回调本身被包装到恢复状态的回调中:

   let state;

   function setTimeoutWithState(cb, time) {
      const closured = state;
      setTimeout(() => {
        state = closured;
        cb();
      }, time);
  }

  state = 1;
  setTimeoutWithState(() => console.log(state), 1000);

  state = 2;
  setTimeoutWithState(() => console.log(state), 500);

现在库只需要以这种方式包装每个异步回调,然后您就可以轻松地维护状态,不是很好吗?可以肯定的是,但是向每个回调添加代码确实是有代价的(因为 JS 大量使用回调)。

【讨论】:

  • 我认为这是一个很好的解释,但您仍然没有展示节点如何解决这个问题。在您的评论中,您说节点不赞成这种传递状态的方式,所以我真的很想知道此时传递请求相关信息的最先进技术。谢谢!
  • 目前没有办法
猜你喜欢
  • 2021-11-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多