GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — async_hooks: move PromiseHook handler to JS · nodejs/node@b061655

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
  • benchmark/async_hooks
    • promises.js
  • doc/api
    • async_hooks.md
  • lib
    • async_hooks.js
    • internal
      • async_hooks.js
  • src
    • async_wrap.cc
    • async_wrap.h
    • env.h
  • test
    • addons/async-hooks-promise
      • test.js
    • parallel
      • test-async-hooks-promise.js
      • test-bootstrap-modules.js
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎benchmark/async_hooks/promises.js‎

Copy file name to clipboardExpand all lines: benchmark/async_hooks/promises.js
+23-4Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,31 @@
22
const common = require('../common.js');
33
const { createHook } = require('async_hooks');
44

5+
let hook;
6+
const tests = {
7+
disabled() {
8+
hook = createHook({
9+
promiseResolve() {}
10+
});
11+
},
12+
enabled() {
13+
hook = createHook({
14+
promiseResolve() {}
15+
}).enable();
16+
},
17+
enabledWithDestroy() {
18+
hook = createHook({
19+
promiseResolve() {},
20+
destroy() {}
21+
}).enable();
22+
}
23+
};
24+
525
const bench = common.createBenchmark(main, {
626
n: [1e6],
727
asyncHooks: [
828
'enabled',
29+
'enabledWithDestroy',
930
'disabled',
1031
]
1132
});
@@ -19,10 +40,8 @@ async function run(n) {
1940
}
2041

2142
function main({ n, asyncHooks }) {
22-
const hook = createHook({ promiseResolve() {} });
23-
if (asyncHooks !== 'disabled') {
24-
hook.enable();
25-
}
43+
if (hook) hook.disable();
44+
tests[asyncHooks]();
2645
bench.start();
2746
run(n).then(() => {
2847
bench.end(n);
Collapse file

‎doc/api/async_hooks.md‎

Copy file name to clipboardExpand all lines: doc/api/async_hooks.md
-5Lines changed: 0 additions & 5 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -306,11 +306,6 @@ currently not considered public, but using the Embedder API, users can provide
306306
and document their own resource objects. For example, such a resource object
307307
could contain the SQL query being executed.
308308

309-
In the case of Promises, the `resource` object will have an
310-
`isChainedPromise` property, set to `true` if the promise has a parent promise,
311-
and `false` otherwise. For example, in the case of `b = a.then(handler)`, `a` is
312-
considered a parent `Promise` of `b`. Here, `b` is considered a chained promise.
313-
314309
In some cases the resource object is reused for performance reasons, it is
315310
thus not safe to use it as a key in a `WeakMap` or add properties to it.
316311

Collapse file

‎lib/async_hooks.js‎

Copy file name to clipboardExpand all lines: lib/async_hooks.js
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ const {
2626
getHookArrays,
2727
enableHooks,
2828
disableHooks,
29+
updatePromiseHookMode,
2930
executionAsyncResource,
3031
// Internal Embedder API
3132
newAsyncId,
@@ -101,6 +102,8 @@ class AsyncHook {
101102
enableHooks();
102103
}
103104

105+
updatePromiseHookMode();
106+
104107
return this;
105108
}
106109

Collapse file

‎lib/internal/async_hooks.js‎

Copy file name to clipboardExpand all lines: lib/internal/async_hooks.js
+71-5Lines changed: 71 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
const {
44
Error,
55
FunctionPrototypeBind,
6+
ObjectPrototypeHasOwnProperty,
67
ObjectDefineProperty,
8+
Promise,
79
Symbol,
810
} = primordials;
911

@@ -86,9 +88,10 @@ const { kInit, kBefore, kAfter, kDestroy, kTotals, kPromiseResolve,
8688
kCheck, kExecutionAsyncId, kAsyncIdCounter, kTriggerAsyncId,
8789
kDefaultTriggerAsyncId, kStackLength } = async_wrap.constants;
8890

91+
const { async_id_symbol,
92+
trigger_async_id_symbol } = internalBinding('symbols');
93+
8994
// Used in AsyncHook and AsyncResource.
90-
const async_id_symbol = Symbol('asyncId');
91-
const trigger_async_id_symbol = Symbol('triggerAsyncId');
9295
const init_symbol = Symbol('init');
9396
const before_symbol = Symbol('before');
9497
const after_symbol = Symbol('after');
@@ -243,27 +246,89 @@ function restoreActiveHooks() {
243246
active_hooks.tmp_fields = null;
244247
}
245248

249+
function trackPromise(promise, parent, silent) {
250+
const asyncId = getOrSetAsyncId(promise);
251+
252+
promise[trigger_async_id_symbol] = parent ? getOrSetAsyncId(parent) :
253+
getDefaultTriggerAsyncId();
254+
255+
if (!silent && initHooksExist()) {
256+
const triggerId = promise[trigger_async_id_symbol];
257+
emitInitScript(asyncId, 'PROMISE', triggerId, promise);
258+
}
259+
}
260+
261+
function fastPromiseHook(type, promise, parent) {
262+
if (type === kInit || !promise[async_id_symbol]) {
263+
const silent = type !== kInit;
264+
if (parent instanceof Promise) {
265+
trackPromise(promise, parent, silent);
266+
} else {
267+
trackPromise(promise, null, silent);
268+
}
269+
270+
if (!silent) return;
271+
}
272+
273+
const asyncId = promise[async_id_symbol];
274+
switch (type) {
275+
case kBefore:
276+
const triggerId = promise[trigger_async_id_symbol];
277+
emitBeforeScript(asyncId, triggerId, promise);
278+
break;
279+
case kAfter:
280+
if (hasHooks(kAfter)) {
281+
emitAfterNative(asyncId);
282+
}
283+
if (asyncId === executionAsyncId()) {
284+
// This condition might not be true if async_hooks was enabled during
285+
// the promise callback execution.
286+
// Popping it off the stack can be skipped in that case, because it is
287+
// known that it would correspond to exactly one call with
288+
// PromiseHookType::kBefore that was not witnessed by the PromiseHook.
289+
popAsyncContext(asyncId);
290+
}
291+
break;
292+
case kPromiseResolve:
293+
emitPromiseResolveNative(asyncId);
294+
break;
295+
}
296+
}
246297

247298
let wantPromiseHook = false;
248299
function enableHooks() {
249300
async_hook_fields[kCheck] += 1;
301+
}
250302

303+
let promiseHookMode = -1;
304+
function updatePromiseHookMode() {
251305
wantPromiseHook = true;
252-
enablePromiseHook();
306+
if (destroyHooksExist()) {
307+
if (promiseHookMode !== 1) {
308+
promiseHookMode = 1;
309+
enablePromiseHook();
310+
}
311+
} else if (promiseHookMode !== 0) {
312+
promiseHookMode = 0;
313+
enablePromiseHook(fastPromiseHook);
314+
}
253315
}
254316

255317
function disableHooks() {
256318
async_hook_fields[kCheck] -= 1;
257319

258320
wantPromiseHook = false;
321+
259322
// Delay the call to `disablePromiseHook()` because we might currently be
260323
// between the `before` and `after` calls of a Promise.
261324
enqueueMicrotask(disablePromiseHookIfNecessary);
262325
}
263326

264327
function disablePromiseHookIfNecessary() {
265-
if (!wantPromiseHook)
328+
if (!wantPromiseHook) {
329+
promiseHookMode = -1;
266330
disablePromiseHook();
331+
}
267332
}
268333

269334
// Internal Embedder API //
@@ -276,7 +341,7 @@ function newAsyncId() {
276341
}
277342

278343
function getOrSetAsyncId(object) {
279-
if (object.hasOwnProperty(async_id_symbol)) {
344+
if (ObjectPrototypeHasOwnProperty(object, async_id_symbol)) {
280345
return object[async_id_symbol];
281346
}
282347

@@ -447,6 +512,7 @@ module.exports = {
447512
},
448513
enableHooks,
449514
disableHooks,
515+
updatePromiseHookMode,
450516
clearDefaultTriggerAsyncId,
451517
clearAsyncIdStack,
452518
hasAsyncIdStack,

0 commit comments

Comments
0 (0)
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.