Working with Async Hooks
1. Creating Async Hooks (async_hooks.createHook)
Example
import async_hooks from "node:async_hooks";
const hook = async_hooks.createHook({
init(asyncId, type, triggerAsyncId, resource) {},
before(asyncId) {},
after(asyncId) {},
destroy(asyncId) {}
});
hook.enable();
2. Using init Callback
| Param | Description |
|---|---|
asyncId | Unique async resource id |
type | e.g. TCPWRAP, Timeout, PROMISE |
triggerAsyncId | Parent context id |
resource | The actual resource |
3. Using before and after Callbacks
| Hook | Fires |
|---|---|
before | Just before resource callback runs |
after | Right after callback returns |
4. Using destroy Callback
| Hook | Fires |
|---|---|
destroy | Resource GC'd or manually destroyed |
promiseResolve | When a promise resolves |
5. Getting Current Execution ID (executionAsyncId)
| API | Returns |
|---|---|
async_hooks.executionAsyncId() | Current async context id |
async_hooks.executionAsyncResource() | Current resource |
6. Getting Trigger Async ID (triggerAsyncId)
| API | Returns |
|---|---|
async_hooks.triggerAsyncId() | Caller's async id |
7. Using AsyncLocalStorage
Example: Per-request store
import { AsyncLocalStorage } from "node:async_hooks";
const als = new AsyncLocalStorage();
http.createServer((req, res) => {
als.run({ requestId: crypto.randomUUID() }, () => handler(req, res));
}).listen(3000);
function log(msg) {
const { requestId } = als.getStore() ?? {};
console.log(requestId, msg);
}
8. Tracking Request Context
| Use | Detail |
|---|---|
| Trace IDs | Pass to logger / spans |
| User identity | Avoid threading through every fn |
| Tenant info | Multi-tenant routing |
9. Debugging Async Operations
| Tool | Purpose |
|---|---|
--async-stack-traces (default) | Cross-await stacks |
| Async hook tracing | Map causal chains |
| OpenTelemetry context | Distributed traces |
10. Understanding Performance Implications
| Concern | Detail |
|---|---|
| Async hooks have overhead | Use sparingly; AsyncLocalStorage is optimized path |
| Don't enable in production | Unless via AsyncLocalStorage |
| Avoid heavy work in callbacks | Runs on every async transition |