Skip to content

Commit fd9497b

Browse files
Stephen Belangertargos
Stephen Belanger
authored andcommitted
lib: improve async_context_frame structure
PR-URL: #54239 Reviewed-By: Gerhard Stöbich <[email protected]> Reviewed-By: Chengzhong Wu <[email protected]>
1 parent a476837 commit fd9497b

File tree

7 files changed

+46
-21
lines changed

7 files changed

+46
-21
lines changed

doc/api/cli.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -884,8 +884,8 @@ added: REPLACEME
884884

885885
> Stability: 1 - Experimental
886886
887-
Enables the use of AsyncLocalStorage backed by AsyncContextFrame rather than
888-
the default implementation which relies on async\_hooks. This new model is
887+
Enables the use of [`AsyncLocalStorage`][] backed by `AsyncContextFrame` rather
888+
than the default implementation which relies on async\_hooks. This new model is
889889
implemented very differently and so could have differences in how context data
890890
flows within the application. As such, it is presently recommended to be sure
891891
your application behaviour is unaffected by this change before using it in
@@ -3528,6 +3528,7 @@ node --stack-trace-limit=12 -p -e "Error.stackTraceLimit" # prints 12
35283528
[`--redirect-warnings`]: #--redirect-warningsfile
35293529
[`--require`]: #-r---require-module
35303530
[`Atomics.wait()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Atomics/wait
3531+
[`AsyncLocalStorage`]: async_context.md#class-asynclocalstorage
35313532
[`Buffer`]: buffer.md#class-buffer
35323533
[`CRYPTO_secure_malloc_init`]: https://www.openssl.org/docs/man3.0/man3/CRYPTO_secure_malloc_init.html
35333534
[`NODE_OPTIONS`]: #node_optionsoptions

lib/async_hooks.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ module.exports = {
280280
// Public API
281281
get AsyncLocalStorage() {
282282
return AsyncContextFrame.enabled ?
283-
require('internal/async_local_storage/native') :
283+
require('internal/async_local_storage/async_context_frame') :
284284
require('internal/async_local_storage/async_hooks');
285285
},
286286
createHook,

lib/internal/async_context_frame.js

Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,27 @@
11
'use strict';
22

3+
const {
4+
ObjectSetPrototypeOf,
5+
} = primordials;
6+
37
const {
48
getContinuationPreservedEmbedderData,
59
setContinuationPreservedEmbedderData,
610
} = internalBinding('async_context_frame');
711

812
let enabled_;
913

10-
class AsyncContextFrame extends Map {
11-
constructor(store, data) {
12-
super(AsyncContextFrame.current());
13-
this.set(store, data);
14-
}
15-
14+
class ActiveAsyncContextFrame {
1615
static get enabled() {
17-
enabled_ ??= require('internal/options')
18-
.getOptionValue('--experimental-async-context-frame');
19-
return enabled_;
16+
return true;
2017
}
2118

2219
static current() {
23-
if (this.enabled) {
24-
return getContinuationPreservedEmbedderData();
25-
}
20+
return getContinuationPreservedEmbedderData();
2621
}
2722

2823
static set(frame) {
29-
if (this.enabled) {
30-
setContinuationPreservedEmbedderData(frame);
31-
}
24+
setContinuationPreservedEmbedderData(frame);
3225
}
3326

3427
static exchange(frame) {
@@ -41,6 +34,37 @@ class AsyncContextFrame extends Map {
4134
const frame = this.current();
4235
frame?.disable(store);
4336
}
37+
}
38+
39+
function checkEnabled() {
40+
const enabled = require('internal/options')
41+
.getOptionValue('--experimental-async-context-frame');
42+
43+
// If enabled, swap to active prototype so we don't need to check status
44+
// on every interaction with the async context frame.
45+
if (enabled) {
46+
// eslint-disable-next-line no-use-before-define
47+
ObjectSetPrototypeOf(AsyncContextFrame, ActiveAsyncContextFrame);
48+
}
49+
50+
return enabled;
51+
}
52+
53+
class AsyncContextFrame extends Map {
54+
constructor(store, data) {
55+
super(AsyncContextFrame.current());
56+
this.set(store, data);
57+
}
58+
59+
static get enabled() {
60+
enabled_ ??= checkEnabled();
61+
return enabled_;
62+
}
63+
64+
static current() {}
65+
static set(frame) {}
66+
static exchange(frame) {}
67+
static disable(store) {}
4468

4569
disable(store) {
4670
this.delete(store);

lib/internal/process/task_queues.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ const { AsyncResource } = require('async_hooks');
4444

4545
const AsyncContextFrame = require('internal/async_context_frame');
4646

47-
const async_context_frame = Symbol('asyncContextFrame');
47+
const async_context_frame = Symbol('kAsyncContextFrame');
4848

4949
// *Must* match Environment::TickInfo::Fields in src/env.h.
5050
const kHasTickScheduled = 0;

lib/internal/timers.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ let debug = require('internal/util/debuglog').debuglog('timer', (fn) => {
123123

124124
const AsyncContextFrame = require('internal/async_context_frame');
125125

126-
const async_context_frame = Symbol('asyncContextFrame');
126+
const async_context_frame = Symbol('kAsyncContextFrame');
127127

128128
// *Must* match Environment::ImmediateInfo::Fields in src/env.h.
129129
const kCount = 0;

src/api/async_resource.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ AsyncResource::AsyncResource(Isolate* isolate,
2727

2828
AsyncResource::~AsyncResource() {
2929
CHECK_NOT_NULL(env_);
30-
env_->RemoveAsyncResourceContextFrame(reinterpret_cast<std::uintptr_t>(this));
3130
EmitAsyncDestroy(env_, async_context_);
31+
env_->RemoveAsyncResourceContextFrame(reinterpret_cast<std::uintptr_t>(this));
3232
}
3333

3434
MaybeLocal<Value> AsyncResource::MakeCallback(Local<Function> callback,

0 commit comments

Comments
 (0)