33const {
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' ) ;
9295const init_symbol = Symbol ( 'init' ) ;
9396const before_symbol = Symbol ( 'before' ) ;
9497const 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
247298let wantPromiseHook = false ;
248299function 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
255317function 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
264327function 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
278343function 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