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.
116
116
Multiple instances can safely exist simultaneously without risk of interfering
117
117
with each other's data.
118
118
119
- ### ` new AsyncLocalStorage() `
119
+ ### ` new AsyncLocalStorage([options] ) `
120
120
121
121
<!-- YAML
122
122
added:
123
123
- v13.10.0
124
124
- v12.17.0
125
125
changes:
126
+ - version: REPLACEME
127
+ pr-url: https://github.com/nodejs/node/pull/57766
128
+ description: Add `defaultValue` and `name` options.
126
129
- version:
127
130
- v19.7.0
128
131
- v18.16.0
@@ -135,6 +138,10 @@ changes:
135
138
description: Add option onPropagate.
136
139
-->
137
140
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
+
138
145
Creates a new instance of ` AsyncLocalStorage ` . Store is only provided within a
139
146
` run() ` call or after an ` enterWith() ` call.
140
147
@@ -286,6 +293,16 @@ emitter.emit('my-event');
286
293
asyncLocalStorage .getStore (); // Returns the same object
287
294
```
288
295
296
+ ### ` asyncLocalStorage.name `
297
+
298
+ <!-- YAML
299
+ added: REPLACEME
300
+ -->
301
+
302
+ * {string}
303
+
304
+ The name of the ` AsyncLocalStorage ` instance if provided.
305
+
289
306
### ` asyncLocalStorage.run(store, callback[, ...args]) `
290
307
291
308
<!-- YAML
Original file line number Diff line number Diff line change @@ -4,10 +4,37 @@ const {
4
4
ReflectApply,
5
5
} = primordials ;
6
6
7
+ const {
8
+ validateObject,
9
+ } = require ( 'internal/validators' ) ;
10
+
7
11
const AsyncContextFrame = require ( 'internal/async_context_frame' ) ;
8
12
const { AsyncResource } = require ( 'async_hooks' ) ;
9
13
10
14
class 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
+
11
38
static bind ( fn ) {
12
39
return AsyncResource . bind ( fn ) ;
13
40
}
@@ -40,7 +67,11 @@ class AsyncLocalStorage {
40
67
}
41
68
42
69
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 ) ;
44
75
}
45
76
}
46
77
Original file line number Diff line number Diff line change 9
9
Symbol,
10
10
} = primordials ;
11
11
12
+ const {
13
+ validateObject,
14
+ } = require ( 'internal/validators' ) ;
15
+
12
16
const {
13
17
AsyncResource,
14
18
createHook,
@@ -27,11 +31,31 @@ const storageHook = createHook({
27
31
} ) ;
28
32
29
33
class 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 = { } ) {
31
46
this . kResourceStore = Symbol ( 'kResourceStore' ) ;
32
47
this . enabled = false ;
48
+ validateObject ( options , 'options' ) ;
49
+ this . #defaultValue = options . defaultValue ;
50
+
51
+ if ( options . name !== undefined ) {
52
+ this . #name = `${ options . name } ` ;
53
+ }
33
54
}
34
55
56
+ /** @type {string } */
57
+ get name ( ) { return this . #name || '' ; }
58
+
35
59
static bind ( fn ) {
36
60
return AsyncResource . bind ( fn ) ;
37
61
}
@@ -109,8 +133,12 @@ class AsyncLocalStorage {
109
133
getStore ( ) {
110
134
if ( this . enabled ) {
111
135
const resource = executionAsyncResource ( ) ;
136
+ if ( ! ( this . kResourceStore in resource ) ) {
137
+ return this . #defaultValue;
138
+ }
112
139
return resource [ this . kResourceStore ] ;
113
140
}
141
+ return this . #defaultValue;
114
142
}
115
143
}
116
144
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