Last active
January 16, 2024 19:09
-
-
Save men232/2a048c98fbeb5d6981f598b0a6a8917f to your computer and use it in GitHub Desktop.
NodeJs provide-inject (vue style)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { AsyncLocalStorage } from 'node:async_hooks'; | |
const ALS = new AsyncLocalStorage(); | |
/** | |
* Execute provided function in async context. | |
* @param {function} fn | |
*/ | |
export function withAppInject(fn) { | |
return ALS.run(new Map(), fn); | |
} | |
/** | |
* @typedef {symbol | string | number | object} ProvideKey | |
* @typedef {unknown} ProvideValue | |
*/ | |
/** | |
* To provide data to a descendants | |
* @param {ProvideKey} key | |
* @param {ProvideValue} value | |
*/ | |
export function provide(key, value) { | |
let store = ALS.getStore(); | |
if (!store) { | |
console.warn(`provide() can only be used inside async context.\n` + captureStackTrace(provide)); | |
return; | |
} | |
store.set(key, value); | |
} | |
/** | |
* @template [T = ProvideValue] | |
* @param {ProvideKey} key | |
* @return {T | undefined} | |
*/ | |
export function inject(key) { | |
const store = ALS.getStore(); | |
if (!store) { | |
console.warn(`inject() can only be used inside async context.\n` + captureStackTrace(inject)); | |
return; | |
} | |
return store.get(key); | |
} | |
/** | |
* Returns true if `inject()` can be used without warning about being called in the wrong place. | |
* @return {boolean} | |
*/ | |
export function hasInjectionContext() { | |
return !!ALS.getStore(); | |
} | |
/** | |
* @param {function} till | |
* @return {string} | |
*/ | |
function captureStackTrace(till) { | |
const err = new Error(''); | |
Error.captureStackTrace(err, till); | |
return err.stack.slice(6); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { withAppInject, provide, inject } from "./appinject.mjs"; | |
for (let idx = 0; idx < 3; idx++) { | |
withAppInject(main).catch(console.error); | |
} | |
async function main() { | |
const requestId = Date.now() + '-' + Math.floor(Math.random() * 1000); // req.headers.get('x-request-id') | |
provide('requestId', requestId); | |
console.log('🏁 [start] req =', requestId); | |
logRequestId(); | |
} | |
function logRequestId() { | |
// Here we will get the same request id (isoltaed) that generated in main function | |
const requestId = inject('requestId'); | |
console.log('🛑 [end] req =', requestId); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { randomUUID } from "node:crypto"; | |
import { hasInjectionContext, inject, provide } from "./appinject.mjs"; | |
/** | |
* Returns previous generated uuid in the same context or the new one | |
* @return {string} | |
*/ | |
export function useTraceId() { | |
if (!hasInjectionContext()) { | |
console.warn( | |
new Error("useTraceId() can only be used inside async context.").stack | |
); | |
return randomUUID(); | |
} | |
let traceId = inject("traceId"); | |
if (traceId) { | |
return traceId; | |
} | |
traceId = randomUUID(); | |
provide("traceId", traceId); | |
return traceId; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment