@@ -40,43 +40,30 @@ export class GCManager {
4040 #forceDisable = false
4141 #eligibleItems = new Set < Removable > ( )
4242 #scheduledScanTimeoutId: ManagedTimerId | null = null
43- #scheduledScanTimeout: number | null = null
44- #scheduledScanIdleCallbackId: ManagedTimerId | null = null
43+ #isScheduledScan = false
4544
4645 constructor ( config : GCManagerConfig = { } ) {
4746 this . #forceDisable = config . forceDisable ?? false
4847 }
4948
5049 #scheduleScan( ) : void {
51- if ( this . #forceDisable) {
50+ if ( this . #forceDisable || this . #isScheduledScan ) {
5251 return
5352 }
5453
55- if ( this . #scheduledScanIdleCallbackId !== null ) {
56- return
57- }
58-
59- if ( this . #isScanning && this . #scheduledScanTimeoutId !== null ) {
60- timeoutManager . clearTimeout ( this . #scheduledScanTimeoutId)
61- this . #isScanning = false
62- this . #scheduledScanTimeoutId = null
63- this . #scheduledScanTimeout = null
64- this . #scheduledScanIdleCallbackId = null
65- }
54+ this . #isScheduledScan = true
6655
67- this . #scheduledScanIdleCallbackId = timeoutManager . setTimeout ( ( ) => {
68- this . #scheduledScanIdleCallbackId = null
56+ queueMicrotask ( ( ) => {
57+ if ( ! this . #isScheduledScan) {
58+ return
59+ }
6960
70- const now = Date . now ( )
61+ this . #isScheduledScan = false
7162
7263 let minTimeUntilGc = Infinity
7364
7465 for ( const item of this . #eligibleItems) {
75- const gcAt = item . getGcAtTimestamp ( )
76- if ( gcAt === null ) {
77- continue
78- }
79- const timeUntilGc = Math . max ( 0 , gcAt - now )
66+ const timeUntilGc = getTimeUntilGc ( item )
8067
8168 if ( timeUntilGc < minTimeUntilGc ) {
8269 minTimeUntilGc = timeUntilGc
@@ -87,20 +74,14 @@ export class GCManager {
8774 return
8875 }
8976
90- if ( this . #scheduledScanTimeout === minTimeUntilGc ) {
91- return
92- }
93-
9477 if ( this . #scheduledScanTimeoutId !== null ) {
9578 timeoutManager . clearTimeout ( this . #scheduledScanTimeoutId)
96- this . #scheduledScanTimeoutId = null
9779 }
9880
81+ this . #isScanning = true
9982 this . #scheduledScanTimeoutId = timeoutManager . setTimeout ( ( ) => {
10083 this . #isScanning = false
10184 this . #scheduledScanTimeoutId = null
102- this . #scheduledScanTimeout = null
103- this . #scheduledScanIdleCallbackId = null
10485
10586 this . #performScan( )
10687
@@ -109,26 +90,23 @@ export class GCManager {
10990 this . #scheduleScan( )
11091 }
11192 } , minTimeUntilGc )
112-
113- this . #isScanning = true
114- this . #scheduledScanTimeout = minTimeUntilGc
115- } , 0 )
93+ } )
11694 }
11795
11896 /**
11997 * Stop periodic scanning. Safe to call multiple times.
12098 */
12199 stopScanning ( ) : void {
100+ this . #isScanning = false
101+ this . #isScheduledScan = false
102+
122103 if ( this . #scheduledScanTimeoutId === null ) {
123104 return
124105 }
125106
126107 timeoutManager . clearTimeout ( this . #scheduledScanTimeoutId)
127108
128- this . #isScanning = false
129109 this . #scheduledScanTimeoutId = null
130- this . #scheduledScanTimeout = null
131- this . #scheduledScanIdleCallbackId = null
132110 }
133111
134112 /**
@@ -145,12 +123,17 @@ export class GCManager {
145123 * @param item - The query or mutation marked for GC
146124 */
147125 trackEligibleItem ( item : Removable ) : void {
148- this . #eligibleItems. add ( item )
126+ if ( this . #forceDisable) {
127+ return
128+ }
149129
150- // Start scanning if we have eligible items and aren't already scanning
151- if ( ! this . #isScanning) {
152- this . #scheduleScan( )
130+ if ( this . #eligibleItems. has ( item ) ) {
131+ return
153132 }
133+
134+ this . #eligibleItems. add ( item )
135+
136+ this . #scheduleScan( )
154137 }
155138
156139 /**
@@ -160,11 +143,22 @@ export class GCManager {
160143 * @param item - The query or mutation no longer eligible for GC
161144 */
162145 untrackEligibleItem ( item : Removable ) : void {
146+ if ( this . #forceDisable) {
147+ return
148+ }
149+
150+ if ( ! this . #eligibleItems. has ( item ) ) {
151+ return
152+ }
153+
163154 this . #eligibleItems. delete ( item )
164155
165- // Stop scanning if no items are eligible
166- if ( this . getEligibleItemCount ( ) === 0 && this . #isScanning) {
167- this . stopScanning ( )
156+ if ( this . isScanning ( ) ) {
157+ if ( this . getEligibleItemCount ( ) === 0 ) {
158+ this . stopScanning ( )
159+ } else {
160+ this . #scheduleScan( )
161+ }
168162 }
169163 }
170164
@@ -183,7 +177,7 @@ export class GCManager {
183177 const wasCollected = item . optionalRemove ( )
184178
185179 if ( wasCollected ) {
186- this . untrackEligibleItem ( item )
180+ this . #eligibleItems . delete ( item )
187181 }
188182 }
189183 } catch ( error ) {
@@ -194,4 +188,17 @@ export class GCManager {
194188 }
195189 }
196190 }
191+
192+ clear ( ) : void {
193+ this . #eligibleItems. clear ( )
194+ this . stopScanning ( )
195+ }
196+ }
197+
198+ function getTimeUntilGc ( item : Removable ) : number {
199+ const gcAt = item . getGcAtTimestamp ( )
200+ if ( gcAt === null ) {
201+ return Infinity
202+ }
203+ return Math . max ( 0 , gcAt - Date . now ( ) )
197204}
0 commit comments