File tree Expand file tree Collapse file tree 5 files changed +159
-3
lines changed
lib/internal/async_local_storage Expand file tree Collapse file tree 5 files changed +159
-3
lines changed Original file line number Diff line number Diff line change @@ -116,13 +116,16 @@ Each instance of `AsyncLocalStorage` maintains an independent storage context.
116116Multiple instances can safely exist simultaneously without risk of interfering
117117with each other's data.
118118
119- ### ` new AsyncLocalStorage() `
119+ ### ` new AsyncLocalStorage([options] ) `
120120
121121<!-- YAML
122122added:
123123 - v13.10.0
124124 - v12.17.0
125125changes:
126+ - version: REPLACEME
127+ pr-url: https://github.com/nodejs/node/pull/57766
128+ description: Add `defaultValue` and `name` options.
126129 - version:
127130 - v19.7.0
128131 - v18.16.0
@@ -135,6 +138,10 @@ changes:
135138 description: Add option onPropagate.
136139-->
137140
141+ * ` options ` {Object}
142+ * ` defaultValue ` {any} The default value to be used when no store is provided.
143+ * ` name ` {string} A name for the ` AsyncLocalStorage ` value.
144+
138145Creates a new instance of ` AsyncLocalStorage ` . Store is only provided within a
139146` run() ` call or after an ` enterWith() ` call.
140147
@@ -286,6 +293,16 @@ emitter.emit('my-event');
286293asyncLocalStorage .getStore (); // Returns the same object
287294```
288295
296+ ### ` asyncLocalStorage.name `
297+
298+ <!-- YAML
299+ added: REPLACEME
300+ -->
301+
302+ * {string}
303+
304+ The name of the ` AsyncLocalStorage ` instance if provided.
305+
289306### ` asyncLocalStorage.run(store, callback[, ...args]) `
290307
291308<!-- YAML
Original file line number Diff line number Diff line change @@ -4,10 +4,37 @@ const {
44 ReflectApply,
55} = primordials ;
66
7+ const {
8+ validateObject,
9+ } = require ( 'internal/validators' ) ;
10+
711const AsyncContextFrame = require ( 'internal/async_context_frame' ) ;
812const { AsyncResource } = require ( 'async_hooks' ) ;
913
1014class AsyncLocalStorage {
15+ #defaultValue = undefined ;
16+ #name = undefined ;
17+
18+ /**
19+ * @typedef {object } AsyncLocalStorageOptions
20+ * @property {any } [defaultValue] - The default value to use when no value is set.
21+ * @property {string } [name] - The name of the storage.
22+ */
23+ /**
24+ * @param {AsyncLocalStorageOptions } [options]
25+ */
26+ constructor ( options = { } ) {
27+ validateObject ( options , 'options' ) ;
28+ this . #defaultValue = options . defaultValue ;
29+
30+ if ( options . name !== undefined ) {
31+ this . #name = `${ options . name } ` ;
32+ }
33+ }
34+
35+ /** @type {string } */
36+ get name ( ) { return this . #name || '' ; }
37+
1138 static bind ( fn ) {
1239 return AsyncResource . bind ( fn ) ;
1340 }
@@ -40,7 +67,11 @@ class AsyncLocalStorage {
4067 }
4168
4269 getStore ( ) {
43- return AsyncContextFrame . current ( ) ?. get ( this ) ;
70+ const frame = AsyncContextFrame . current ( ) ;
71+ if ( ! frame ?. has ( this ) ) {
72+ return this . #defaultValue;
73+ }
74+ return frame ?. get ( this ) ;
4475 }
4576}
4677
Original file line number Diff line number Diff line change 99 Symbol,
1010} = primordials ;
1111
12+ const {
13+ validateObject,
14+ } = require ( 'internal/validators' ) ;
15+
1216const {
1317 AsyncResource,
1418 createHook,
@@ -27,11 +31,31 @@ const storageHook = createHook({
2731} ) ;
2832
2933class AsyncLocalStorage {
30- constructor ( ) {
34+ #defaultValue = undefined ;
35+ #name = undefined ;
36+
37+ /**
38+ * @typedef {object } AsyncLocalStorageOptions
39+ * @property {any } [defaultValue] - The default value to use when no value is set.
40+ * @property {string } [name] - The name of the storage.
41+ */
42+ /**
43+ * @param {AsyncLocalStorageOptions } [options]
44+ */
45+ constructor ( options = { } ) {
3146 this . kResourceStore = Symbol ( 'kResourceStore' ) ;
3247 this . enabled = false ;
48+ validateObject ( options , 'options' ) ;
49+ this . #defaultValue = options . defaultValue ;
50+
51+ if ( options . name !== undefined ) {
52+ this . #name = `${ options . name } ` ;
53+ }
3354 }
3455
56+ /** @type {string } */
57+ get name ( ) { return this . #name || '' ; }
58+
3559 static bind ( fn ) {
3660 return AsyncResource . bind ( fn ) ;
3761 }
@@ -109,8 +133,12 @@ class AsyncLocalStorage {
109133 getStore ( ) {
110134 if ( this . enabled ) {
111135 const resource = executionAsyncResource ( ) ;
136+ if ( ! ( this . kResourceStore in resource ) ) {
137+ return this . #defaultValue;
138+ }
112139 return resource [ this . kResourceStore ] ;
113140 }
141+ return this . #defaultValue;
114142 }
115143}
116144
Original file line number Diff line number Diff line change 1+ // Flags: --no-async-context-frame
2+ 'use strict' ;
3+
4+ require ( '../common' ) ;
5+
6+ const {
7+ AsyncLocalStorage,
8+ } = require ( 'async_hooks' ) ;
9+
10+ const {
11+ strictEqual,
12+ throws,
13+ } = require ( 'assert' ) ;
14+
15+ // ============================================================================
16+ // The defaultValue option
17+ const als1 = new AsyncLocalStorage ( ) ;
18+ strictEqual ( als1 . getStore ( ) , undefined , 'value should be undefined' ) ;
19+
20+ const als2 = new AsyncLocalStorage ( { defaultValue : 'default' } ) ;
21+ strictEqual ( als2 . getStore ( ) , 'default' , 'value should be "default"' ) ;
22+
23+ const als3 = new AsyncLocalStorage ( { defaultValue : 42 } ) ;
24+ strictEqual ( als3 . getStore ( ) , 42 , 'value should be 42' ) ;
25+
26+ const als4 = new AsyncLocalStorage ( { defaultValue : null } ) ;
27+ strictEqual ( als4 . getStore ( ) , null , 'value should be null' ) ;
28+
29+ throws ( ( ) => new AsyncLocalStorage ( null ) , {
30+ code : 'ERR_INVALID_ARG_TYPE' ,
31+ } ) ;
32+
33+ // ============================================================================
34+ // The name option
35+
36+ const als5 = new AsyncLocalStorage ( { name : 'test' } ) ;
37+ strictEqual ( als5 . name , 'test' ) ;
38+
39+ const als6 = new AsyncLocalStorage ( ) ;
40+ strictEqual ( als6 . name , '' ) ;
Original file line number Diff line number Diff line change 1+ // Flags: --async-context-frame
2+ 'use strict' ;
3+
4+ require ( '../common' ) ;
5+
6+ const {
7+ AsyncLocalStorage,
8+ } = require ( 'async_hooks' ) ;
9+
10+ const {
11+ strictEqual,
12+ throws,
13+ } = require ( 'assert' ) ;
14+
15+ // ============================================================================
16+ // The defaultValue option
17+ const als1 = new AsyncLocalStorage ( ) ;
18+ strictEqual ( als1 . getStore ( ) , undefined , 'value should be undefined' ) ;
19+
20+ const als2 = new AsyncLocalStorage ( { defaultValue : 'default' } ) ;
21+ strictEqual ( als2 . getStore ( ) , 'default' , 'value should be "default"' ) ;
22+
23+ const als3 = new AsyncLocalStorage ( { defaultValue : 42 } ) ;
24+ strictEqual ( als3 . getStore ( ) , 42 , 'value should be 42' ) ;
25+
26+ const als4 = new AsyncLocalStorage ( { defaultValue : null } ) ;
27+ strictEqual ( als4 . getStore ( ) , null , 'value should be null' ) ;
28+
29+ throws ( ( ) => new AsyncLocalStorage ( null ) , {
30+ code : 'ERR_INVALID_ARG_TYPE' ,
31+ } ) ;
32+
33+ // ============================================================================
34+ // The name option
35+
36+ const als5 = new AsyncLocalStorage ( { name : 'test' } ) ;
37+ strictEqual ( als5 . name , 'test' ) ;
38+
39+ const als6 = new AsyncLocalStorage ( ) ;
40+ strictEqual ( als6 . name , '' ) ;
You can’t perform that action at this time.
0 commit comments