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,
0 commit comments