AsyncLocalStorage doesn't work with async/await
Description of Bug
AsyncLocalStorage doesn't work well with async/await
Steps to Reproduce
- Go to https://stackblitz.com/edit/stackblitz-starters-pkxqds?file=index.mjs
import { AsyncLocalStorage } from 'node:async_hooks'; const asyncLocalStorage = new AsyncLocalStorage(); asyncLocalStorage.run('hello', () => { console.log('store before:', asyncLocalStorage.getStore()); setTimeout(() => { console.log('store after:', asyncLocalStorage.getStore()); }, 1); }); asyncLocalStorage.run('hello', async () => { console.log('store async before:', asyncLocalStorage.getStore()); await new Promise((r) => setTimeout(r, 1)); console.log('store async after:', asyncLocalStorage.getStore()); }); - Run
node index.mjs - Observe output
store before: hello store async before: hello store after: hello store async after: undefined - Running the same script locally produces output
(Running under Node.js v16.20.0 on MacOS)store before: hello store async before: hello store after: hello store async after: hello
Expected Behavior
AsyncLocalStorage in stackblitz works with async/await.
Hi @Janpot ! Thanks for opening this issue!
You are correct! AsyncLocalStorage does not currently works in StackBlitz. This is because we don't really have an implementation for async hooks and promise hooks. We have ideas about how to do that but we want to make sure it wouldn't impact performance too much.
We'll keep this issue open and keep you posted!
Thank you @Nemikolh. Are there any recommended ways to detect whether my package is running under Stackblitz?
Yes! You can use @webcontainer/env. It exposes a function isWebContainer() that works both on Node and in WebContainer.
Related to https://github.com/nuxt/nuxt/issues/23032, it would be nice that if AsyncLocalStorage mock shows a one time warning while we are waiting for AsyncContext native support in browsers so that framework users implicitly relying on this API, consider that it is an unsupported platform feature instead of silently getting and error.
Is there any update on this?
@birkskyum Last time I checked with the team, it needed native browser support. The best thing we might hope is to wait for AsyncContext proposal to move forward and browsers to implement it.
In the proposal it states:
Furthermore, the async/await syntax bypasses the userland Promises and makes it impossible for existing tools like Zone.js that instruments the Promise to work with it without transpilation.
@mgechev do you have any idea about the horizon for Angular to sunset/revamp zone.js? I've struggled with it not being compatible with modern ts compile targets, so it's holding the ecosystem back in multiple dimensions, now all the way to the tc39 proposals well beyond angular.
Has anyone been able to get a polyfill working? I've tried this plugin I built, but still no luck:
function alsShim() {
return {
name: 'virtual-async-hooks',
resolveId(id) {
if (id === '\0virtual:async_hooks') return id;
},
load(id) {
if (id !== '\0virtual:async_hooks') return null;
console.log('loaded!', id);
// Browser-friendly shim
return `
import AsyncContext from "@webfill/async-context";
console.log('hello!')
export class AsyncLocalStorage {
#var = new AsyncContext.Variable({ defaultValue: undefined });
run(store, fn, ...args) {
console.log('Run', store)
return this.#var.run(store, fn, ...args);
}
getStore() {
console.trace('Get Store', this, this.#var.get())
return this.#var.get();
}
enterWith(store) {
this.#var.run(store, () => {});
}
disable() {}
enable() {}
}
export default { AsyncLocalStorage };
`;
},
};
}