@@ -27,18 +27,27 @@ export const enum DispatcherState {
2727
2828// The possible commands to be processed by the dispatcher.
2929const enum Commands {
30- // The dispatcher must enqueue a new task.
30+ // The dispatcher will enqueue a new task.
3131 //
3232 // This command is always followed by a concrete task for the dispatcher to execute.
3333 Task ,
34+ // Same as the `Task` command,
35+ // but the task enqueued by this command is not cleared by the `Clear` command.
36+ //
37+ // # Note
38+ //
39+ // `Shutdown` will still clear these tasks.
40+ //
41+ // Unless unavoidable, prefer using the normal `Task`.
42+ PersistentTask ,
3443 // The dispatcher should stop executing the queued tasks.
3544 Stop ,
3645 // The dispatcher should stop executing the queued tasks and clear the queue.
3746 Clear ,
3847 // The dispatcher will clear the queue and go into the Shutdown state.
3948 Shutdown ,
4049 // Exactly like a normal Task, but spawned for tests.
41- TestTask ,
50+ TestTask = "TestTask" ,
4251}
4352
4453// A task the dispatcher knows how to execute.
@@ -47,13 +56,13 @@ type Task = () => Promise<void>;
4756// An executable command.
4857type Command = {
4958 task : Task ,
50- command : Commands . Task ,
59+ command : Commands . Task | Commands . PersistentTask ,
5160} | {
5261 resolver : ( value : void | PromiseLike < void > ) => void ,
5362 task : Task ,
5463 command : Commands . TestTask ,
5564} | {
56- command : Exclude < Commands , Commands . Task | Commands . TestTask > ,
65+ command : Exclude < Commands , Commands . Task | Commands . TestTask | Commands . PersistentTask > ,
5766} ;
5867
5968/**
@@ -98,6 +107,19 @@ class Dispatcher {
98107 }
99108 }
100109
110+ /**
111+ * Resolve all test resolvers.
112+ *
113+ * Used before clearing the queue in on a `Shutdown` or `Clear` command.
114+ */
115+ private unblockTestResolvers ( ) : void {
116+ this . queue . forEach ( c => {
117+ if ( c . command === Commands . TestTask ) {
118+ c . resolver ( ) ;
119+ }
120+ } ) ;
121+ }
122+
101123 /**
102124 * Executes all the commands in the queue, from oldest to newest.
103125 */
@@ -109,27 +131,23 @@ class Dispatcher {
109131 this . state = DispatcherState . Stopped ;
110132 return ;
111133 case ( Commands . Shutdown ) :
112- case ( Commands . Clear ) :
113- // Unblock test resolvers before clearing the queue.
114- this . queue . forEach ( c => {
115- if ( c . command === Commands . TestTask ) {
116- c . resolver ( ) ;
117- }
118- } ) ;
119-
134+ this . unblockTestResolvers ( ) ;
120135 this . queue = [ ] ;
121- if ( nextCommand . command === Commands . Clear ) {
122- this . state = DispatcherState . Stopped ;
123- } else {
124- this . state = DispatcherState . Shutdown ;
125- }
126-
136+ this . state = DispatcherState . Shutdown ;
127137 return ;
138+ case ( Commands . Clear ) :
139+ this . unblockTestResolvers ( ) ;
140+ this . queue = this . queue . filter ( c =>
141+ [ Commands . PersistentTask , Commands . Shutdown ] . includes ( c . command )
142+ ) ;
143+ nextCommand = this . getNextCommand ( ) ;
144+ continue ;
128145 case ( Commands . TestTask ) :
129146 await this . executeTask ( nextCommand . task ) ;
130147 nextCommand . resolver ( ) ;
131148 nextCommand = this . getNextCommand ( ) ;
132149 continue ;
150+ case ( Commands . PersistentTask ) :
133151 case ( Commands . Task ) :
134152 await this . executeTask ( nextCommand . task ) ;
135153 nextCommand = this . getNextCommand ( ) ;
@@ -237,6 +255,19 @@ class Dispatcher {
237255 } ) ;
238256 }
239257
258+ /**
259+ * Works exactly like {@link launch},
260+ * but enqueues a persistent task which is not cleared by the Clear command.
261+ *
262+ * @param task The task to enqueue.
263+ */
264+ launchPersistent ( task : Task ) : void {
265+ this . launchInternal ( {
266+ task,
267+ command : Commands . PersistentTask
268+ } ) ;
269+ }
270+
240271 /**
241272 * Flushes the tasks enqueued while the dispatcher was uninitialized.
242273 *
@@ -268,9 +299,8 @@ class Dispatcher {
268299 /**
269300 * Enqueues a Clear command at the front of the queue and triggers execution.
270301 *
271- * The Clear command will remove all other tasks from the queue
272- * and put the dispatcher in a Stopped state after the command is executed.
273- * In order to re-start the dispatcher, call the `resume` method.
302+ * The Clear command will remove all other tasks
303+ * except for persistent tasks or shutdown tasks.
274304 *
275305 * # Note
276306 *
@@ -311,7 +341,7 @@ class Dispatcher {
311341 * Shutsdown the dispatcher.
312342 *
313343 * 1. Executes all tasks launched prior to this one.
314- * 2. Clears the queue of any tasks launched after this one.
344+ * 2. Clears the queue of any tasks launched after this one (even persistent tasks) .
315345 * 3. Puts the dispatcher in the `Shutdown` state.
316346 *
317347 * # Note
@@ -356,9 +386,10 @@ class Dispatcher {
356386 return ;
357387 }
358388
389+ // Clear queue.
359390 this . clear ( ) ;
360- // We need to wait for the clear command to be executed .
361- await this . testBlockOnQueue ( ) ;
391+ // Wait for the clear command and any persistent tasks that may still be in the queue .
392+ await this . shutdown ( ) ;
362393 this . state = DispatcherState . Uninitialized ;
363394 }
364395
0 commit comments