@@ -121,6 +121,8 @@ let debug = require('internal/util/debuglog').debuglog('timer', (fn) => {
121121 debug = fn ;
122122} ) ;
123123
124+ let asyncHooks = null ;
125+
124126// *Must* match Environment::ImmediateInfo::Fields in src/env.h.
125127const kCount = 0 ;
126128const kRefCount = 1 ;
@@ -164,6 +166,7 @@ function initAsyncResource(resource, type) {
164166 if ( initHooksExist ( ) )
165167 emitInit ( asyncId , type , triggerAsyncId , resource ) ;
166168}
169+
167170class Timeout {
168171 // Timer constructor function.
169172 // The entire prototype is defined in lib/timers.js
@@ -429,6 +432,20 @@ function setPosition(node, pos) {
429432 node . priorityQueuePosition = pos ;
430433}
431434
435+ function removeAllStores ( timer ) {
436+ // TODO(mcollina): move the list of stores to private
437+ asyncHooks ??= require ( 'async_hooks' ) ;
438+
439+ // TODO(mcollina): this does a copy for safety, we
440+ // should be fast and unsafe.
441+ const activeStores = asyncHooks . getActiveStores ( ) ;
442+
443+ // Use for loop for speed
444+ for ( let i = 0 ; i < activeStores . length ; i ++ ) {
445+ timer [ activeStores [ i ] . kResourceStore ] = undefined ;
446+ }
447+ }
448+
432449function getTimerCallbacks ( runNextTicks ) {
433450 // If an uncaught exception was thrown during execution of immediateQueue,
434451 // this queue will store all remaining Immediates that need to run upon
@@ -594,6 +611,9 @@ function getTimerCallbacks(runNextTicks) {
594611 if ( timer [ kRefed ] )
595612 timeoutInfo [ 0 ] -- ;
596613
614+ removeAllStores ( timer ) ;
615+ timer . _onTimeout = undefined ;
616+
597617 if ( destroyHooksExist ( ) )
598618 emitDestroy ( asyncId ) ;
599619 }
0 commit comments