| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent cc5c8e0 commit b061655
10 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -2,10 +2,31 @@ | |||
| 2 | 2 | const common = require('../common.js'); | |
| 3 | 3 | const { createHook } = require('async_hooks'); | |
| 4 | 4 | ||
| 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 | + | ||
| 5 | 25 | const bench = common.createBenchmark(main, { | |
| 6 | 26 | n: [1e6], | |
| 7 | 27 | asyncHooks: [ | |
| 8 | 28 | 'enabled', | |
| 29 | + 'enabledWithDestroy', | ||
| 9 | 30 | 'disabled', | |
| 10 | 31 | ] | |
| 11 | 32 | }); | |
@@ -19,10 +40,8 @@ async function run(n) { | |||
| 19 | 40 | } | |
| 20 | 41 | ||
| 21 | 42 | 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](); | ||
| 26 | 45 | bench.start(); | |
| 27 | 46 | run(n).then(() => { | |
| 28 | 47 | bench.end(n); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -306,11 +306,6 @@ currently not considered public, but using the Embedder API, users can provide | |||
| 306 | 306 | and document their own resource objects. For example, such a resource object | |
| 307 | 307 | could contain the SQL query being executed. | |
| 308 | 308 | ||
| 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 | - | ||
| 314 | 309 | In some cases the resource object is reused for performance reasons, it is | |
| 315 | 310 | thus not safe to use it as a key in a `WeakMap` or add properties to it. | |
| 316 | 311 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -26,6 +26,7 @@ const { | |||
| 26 | 26 | getHookArrays, | |
| 27 | 27 | enableHooks, | |
| 28 | 28 | disableHooks, | |
| 29 | + updatePromiseHookMode, | ||
| 29 | 30 | executionAsyncResource, | |
| 30 | 31 | // Internal Embedder API | |
| 31 | 32 | newAsyncId, | |
@@ -101,6 +102,8 @@ class AsyncHook { | |||
| 101 | 102 | enableHooks(); | |
| 102 | 103 | } | |
| 103 | 104 | ||
| 105 | + updatePromiseHookMode(); | ||
| 106 | + | ||
| 104 | 107 | return this; | |
| 105 | 108 | } | |
| 106 | 109 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -3,7 +3,9 @@ | |||
| 3 | 3 | const { | |
| 4 | 4 | Error, | |
| 5 | 5 | FunctionPrototypeBind, | |
| 6 | + ObjectPrototypeHasOwnProperty, | ||
| 6 | 7 | ObjectDefineProperty, | |
| 8 | + Promise, | ||
| 7 | 9 | Symbol, | |
| 8 | 10 | } = primordials; | |
| 9 | 11 | ||
@@ -86,9 +88,10 @@ const { kInit, kBefore, kAfter, kDestroy, kTotals, kPromiseResolve, | |||
| 86 | 88 | kCheck, kExecutionAsyncId, kAsyncIdCounter, kTriggerAsyncId, | |
| 87 | 89 | kDefaultTriggerAsyncId, kStackLength } = async_wrap.constants; | |
| 88 | 90 | ||
| 91 | + const { async_id_symbol, | ||
| 92 | + trigger_async_id_symbol } = internalBinding('symbols'); | ||
| 93 | + | ||
| 89 | 94 | // Used in AsyncHook and AsyncResource. | |
| 90 | - const async_id_symbol = Symbol('asyncId'); | ||
| 91 | - const trigger_async_id_symbol = Symbol('triggerAsyncId'); | ||
| 92 | 95 | const init_symbol = Symbol('init'); | |
| 93 | 96 | const before_symbol = Symbol('before'); | |
| 94 | 97 | const after_symbol = Symbol('after'); | |
@@ -243,27 +246,89 @@ function restoreActiveHooks() { | |||
| 243 | 246 | active_hooks.tmp_fields = null; | |
| 244 | 247 | } | |
| 245 | 248 | ||
| 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 | + } | ||
| 246 | 297 | ||
| 247 | 298 | let wantPromiseHook = false; | |
| 248 | 299 | function enableHooks() { | |
| 249 | 300 | async_hook_fields[kCheck] += 1; | |
| 301 | + } | ||
| 250 | 302 | ||
| 303 | + let promiseHookMode = -1; | ||
| 304 | + function updatePromiseHookMode() { | ||
| 251 | 305 | 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 | + } | ||
| 253 | 315 | } | |
| 254 | 316 | ||
| 255 | 317 | function disableHooks() { | |
| 256 | 318 | async_hook_fields[kCheck] -= 1; | |
| 257 | 319 | ||
| 258 | 320 | wantPromiseHook = false; | |
| 321 | + | ||
| 259 | 322 | // Delay the call to `disablePromiseHook()` because we might currently be | |
| 260 | 323 | // between the `before` and `after` calls of a Promise. | |
| 261 | 324 | enqueueMicrotask(disablePromiseHookIfNecessary); | |
| 262 | 325 | } | |
| 263 | 326 | ||
| 264 | 327 | function disablePromiseHookIfNecessary() { | |
| 265 | - if (!wantPromiseHook) | ||
| 328 | + if (!wantPromiseHook) { | ||
| 329 | + promiseHookMode = -1; | ||
| 266 | 330 | disablePromiseHook(); | |
| 331 | + } | ||
| 267 | 332 | } | |
| 268 | 333 | ||
| 269 | 334 | // Internal Embedder API // | |
@@ -276,7 +341,7 @@ function newAsyncId() { | |||
| 276 | 341 | } | |
| 277 | 342 | ||
| 278 | 343 | function getOrSetAsyncId(object) { | |
| 279 | - if (object.hasOwnProperty(async_id_symbol)) { | ||
| 344 | + if (ObjectPrototypeHasOwnProperty(object, async_id_symbol)) { | ||
| 280 | 345 | return object[async_id_symbol]; | |
| 281 | 346 | } | |
| 282 | 347 | ||
@@ -447,6 +512,7 @@ module.exports = { | |||
| 447 | 512 | }, | |
| 448 | 513 | enableHooks, | |
| 449 | 514 | disableHooks, | |
| 515 | + updatePromiseHookMode, | ||
| 450 | 516 | clearDefaultTriggerAsyncId, | |
| 451 | 517 | clearAsyncIdStack, | |
| 452 | 518 | hasAsyncIdStack, | |
| Back | FazBrowse Home | New Git URL |
0 commit comments