@@ -26,10 +26,10 @@ const { pushAsyncIds, popAsyncIds } = async_wrap;
2626// Using var instead of (preferably const) in order to assign
2727// tmp_active_hooks_array if a hook is enabled/disabled during hook execution.
2828var active_hooks_array = [ ] ;
29- // Track whether a hook callback is currently being processed. Used to make
30- // sure active_hooks_array isn't altered in mid execution if another hook is
31- // added or removed.
32- var processing_hook = false ;
29+ // Use a counter to track whether a hook callback is currently being processed.
30+ // Used to make sure active_hooks_array isn't altered in mid execution if
31+ // another hook is added or removed. A counter is used to track nested calls .
32+ var processing_hook = 0 ;
3333// Use to temporarily store and updated active_hooks_array if the user enables
3434// or disables a hook while hooks are being processed.
3535var tmp_active_hooks_array = null ;
@@ -151,7 +151,7 @@ class AsyncHook {
151151
152152
153153function getHookArrays ( ) {
154- if ( ! processing_hook )
154+ if ( processing_hook === 0 )
155155 return [ active_hooks_array , async_hook_fields ] ;
156156 // If this hook is being enabled while in the middle of processing the array
157157 // of currently active hooks then duplicate the current set of active hooks
@@ -342,7 +342,7 @@ function emitHookFactory(symbol, name) {
342342 // before this is called.
343343 // eslint-disable-next-line func-style
344344 const fn = function ( asyncId ) {
345- processing_hook = true ;
345+ processing_hook += 1 ;
346346 // Use a single try/catch for all hook to avoid setting up one per
347347 // iteration.
348348 try {
@@ -353,10 +353,11 @@ function emitHookFactory(symbol, name) {
353353 }
354354 } catch ( e ) {
355355 fatalError ( e ) ;
356+ } finally {
357+ processing_hook -= 1 ;
356358 }
357- processing_hook = false ;
358359
359- if ( tmp_active_hooks_array !== null ) {
360+ if ( processing_hook === 0 && tmp_active_hooks_array !== null ) {
360361 restoreTmpHooks ( ) ;
361362 }
362363 } ;
@@ -422,7 +423,7 @@ function emitDestroyS(asyncId) {
422423// slim chance of the application remaining stable after handling one of these
423424// exceptions.
424425function init ( asyncId , type , triggerAsyncId , resource ) {
425- processing_hook = true ;
426+ processing_hook += 1 ;
426427 // Use a single try/catch for all hook to avoid setting up one per iteration.
427428 try {
428429 for ( var i = 0 ; i < active_hooks_array . length ; i ++ ) {
@@ -435,11 +436,18 @@ function init(asyncId, type, triggerAsyncId, resource) {
435436 }
436437 } catch ( e ) {
437438 fatalError ( e ) ;
439+ } finally {
440+ processing_hook -= 1 ;
438441 }
439- processing_hook = false ;
440442
441- // Isn't null if hooks were added/removed while the hooks were running.
442- if ( tmp_active_hooks_array !== null ) {
443+ // * `tmp_active_hooks_array` is null if no hooks were added/removed while
444+ // the hooks were running. In that case no restoration is needed.
445+ // * In the case where another hook was added/removed while the hooks were
446+ // running and a handle was created causing the `init` hooks to fire again,
447+ // then `restoreTmpHooks` should not be called for the nested `hooks`.
448+ // Otherwise `active_hooks_array` can change during execution of the
449+ // `hooks`.
450+ if ( processing_hook === 0 && tmp_active_hooks_array !== null ) {
443451 restoreTmpHooks ( ) ;
444452 }
445453}
0 commit comments