Skip to content

Commit 604d429

Browse files
author
Stephen Belanger
committed
lib: improve async_context_frame structure
1 parent d1229ee commit 604d429

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
@@ -894,8 +894,8 @@ added: REPLACEME
894894

895895
> Stability: 1 - Experimental
896896
897-
Enables the use of AsyncLocalStorage backed by AsyncContextFrame rather than
898-
the default implementation which relies on async\_hooks. This new model is
897+
Enables the use of [`AsyncLocalStorage`][] backed by `AsyncContextFrame` rather
898+
than the default implementation which relies on async\_hooks. This new model is
899899
implemented very differently and so could have differences in how context data
900900
flows within the application. As such, it is presently recommended to be sure
901901
your application behaviour is unaffected by this change before using it in
@@ -3472,6 +3472,7 @@ node --stack-trace-limit=12 -p -e "Error.stackTraceLimit" # prints 12
34723472
[`--print`]: #-p---print-script
34733473
[`--redirect-warnings`]: #--redirect-warningsfile
34743474
[`--require`]: #-r---require-module
3475+
[`AsyncLocalStorage`]: async_context.md#class-asynclocalstorage
34753476
[`Buffer`]: buffer.md#class-buffer
34763477
[`CRYPTO_secure_malloc_init`]: https://www.openssl.org/docs/man3.0/man3/CRYPTO_secure_malloc_init.html
34773478
[`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
@@ -124,7 +124,7 @@ let debug = require('internal/util/debuglog').debuglog('timer', (fn) => {
124124

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

127-
const async_context_frame = Symbol('asyncContextFrame');
127+
const async_context_frame = Symbol('kAsyncContextFrame');
128128

129129
// *Must* match Environment::ImmediateInfo::Fields in src/env.h.
130130
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)