提问人:BlueSialia 提问时间:9/22/2023 更新时间:9/23/2023 访问量:60
如果异步本地存储在子线程中进行了修改,为什么它会在父线程中更改?
Why does the Async Local Storage change in the parent thread if it is modified in a child thread?
问:
我在 Node.js HTTP 服务器中使用异步本地存储,以便为每个请求创建一个唯一的存储。我的理解是,当我执行异步函数时,子线程(即异步函数内部)将具有与父线程相同的存储,但是当子线程对其进行任何修改时,更改不会传播到父线程。
但我用以下代码尝试了它:
const als = new AsyncLocalStorage<any>();
const wait = (seconds: number) =>
new Promise(res => setTimeout(res, seconds * 1000));
als.run(new Map(), async () => {
als.getStore().set('key', 1);
console.log('outside', als.getStore().get('key'));
foo();
bar();
await wait(2);
console.log('outside', als.getStore().get('key'));
});
async function foo(): Promise<void> {
return new Promise(async (resolve, _) => {
console.log('inside foo', als.getStore().get('key'));
await wait(1);
als.getStore().set('key', 2);
console.log('inside foo', als.getStore().get('key'));
resolve();
});
}
async function bar(): Promise<void> {
return new Promise(async (resolve, _) => {
console.log('inside bar', als.getStore().get('key'));
await wait(1);
als.getStore().set('key', 3);
console.log('inside bar', als.getStore().get('key'));
resolve();
});
}
控制台显示:
outside 1
inside foo 1
inside bar 1
inside foo 2
inside bar 3
outside 3
我本来以为最后一行是.我对异步本地存储的理解有误吗?outside 1
如果是这样,是否有可能实现我的期望?
答:
1赞
Bergi
9/23/2023
#1
您需要区分上下文和可变存储。当子项使用新值进入新上下文时,这确实不会影响父执行的上下文。但在您的示例中,您只输入一个上下文,并在其中存储一个在父级和子级之间共享的上下文。通过设置键值对来修改该映射会修改也与父级共享的单个实例。new Map()
Map
您可能根本不想使用 a。相反,请使用 or 创建新上下文,并将计数器直接存储为上下文值:Map
enterWith
run
const als = new AsyncLocalStorage<any>();
const wait = (seconds: number) =>
new Promise(res => setTimeout(res, seconds * 1000));
als.run(1, async () => {
console.log('outside', als.getStore());
foo();
bar();
await wait(2);
console.log('outside', als.getStore()); // still 1!
});
async function foo(): Promise<void> {
console.log('inside foo', als.getStore()); // 1
await wait(1);
als.enterWith(2);
console.log('inside foo', als.getStore()); // now 2
}
async function bar(): Promise<void> {
console.log('inside bar', als.getStore()); // 1
als.run(3, async () => {
await wait(1);
console.log('inside bar', als.getStore()); // 3 in here
});
}
你会想要 ,因为如果你把它放在第一个函数调用之前,就会影响后续的函数调用(尝试交换 and 语句,看看会发生什么)。run()
enterWith()
await
async function
await wait(1);
als.enterWith(2);
foo
评论
new Map()
异步函数
作为执行器传递给新的 Promise
!