0
# Timer Coordination
1
2
Promise-based timer system with event-driven resolution for scheduling and synchronization in plugin architectures. Provides Clock and Timer classes for managing asynchronous operations, timeouts, and coordination between different parts of the system.
3
4
## Capabilities
5
6
### Clock Class
7
8
Container that manages timer instances and provides access to timing operations. Acts as a central registry for all timers in the system.
9
10
```typescript { .api }
11
/**
12
* Clock manages timer instances and provides timing coordination
13
*/
14
class Clock {
15
/** Internal timer storage (readonly) */
16
readonly store: TimerMap;
17
18
/** Get a timer from the clock by timer type, throws if not found */
19
get(timer: TimerType): Timer;
20
/** Remove a timer from the clock by timer type */
21
remove(timer: TimerType): void;
22
/** Check if the clock has a timer by timer type */
23
has(timer: TimerType): boolean;
24
}
25
```
26
27
**Usage Examples:**
28
29
```typescript
30
import { Clock, createTimer } from "@milkdown/ctx";
31
32
const clock = new Clock();
33
const loadTimer = createTimer("data-load", 5000);
34
35
// Create timer in clock
36
loadTimer.create(clock.store);
37
38
// Check if timer exists
39
if (clock.has(loadTimer)) {
40
const timer = clock.get(loadTimer);
41
console.log("Timer status:", timer.status); // "pending"
42
}
43
44
// Remove timer
45
clock.remove(loadTimer);
46
```
47
48
### Timer Class
49
50
Promise-based timer that can be resolved externally through event dispatching. Supports timeout mechanisms and status tracking.
51
52
```typescript { .api }
53
/**
54
* Timer provides promise-based timing with event-driven resolution
55
*/
56
class Timer {
57
/** The timer type definition (readonly) */
58
readonly type: TimerType;
59
/** Current timer status: pending, resolved, or rejected (readonly) */
60
readonly status: TimerStatus;
61
62
/** Start the timer and return a promise that resolves when done() is called */
63
start(): Promise<void>;
64
/** Resolve the timer by dispatching a custom event */
65
done(): void;
66
}
67
68
type TimerStatus = 'pending' | 'resolved' | 'rejected';
69
```
70
71
**Usage Examples:**
72
73
```typescript
74
import { Clock, createTimer } from "@milkdown/ctx";
75
76
const clock = new Clock();
77
const processTimer = createTimer("process-data", 10000);
78
const timer = processTimer.create(clock.store);
79
80
// Start timer
81
const timerPromise = timer.start();
82
83
console.log("Timer status:", timer.status); // "pending"
84
85
// Resolve timer after some operation
86
setTimeout(() => {
87
timer.done();
88
console.log("Timer status:", timer.status); // "resolved"
89
}, 2000);
90
91
// Wait for completion
92
timerPromise.then(() => {
93
console.log("Timer completed successfully!");
94
}).catch((error) => {
95
console.error("Timer timed out:", error.message);
96
});
97
```
98
99
### TimerType Class
100
101
Type definition for creating timer instances with specified names and timeout durations.
102
103
```typescript { .api }
104
/**
105
* TimerType defines the structure for creating timer instances
106
*/
107
class TimerType {
108
/** Unique identifier for the timer type (readonly) */
109
readonly id: symbol;
110
/** Human-readable timer name (readonly) */
111
readonly name: string;
112
/** Timeout duration in milliseconds (readonly) */
113
readonly timeout: number;
114
115
/** Create a timer type with name and optional timeout (default 3000ms) */
116
constructor(name: string, timeout?: number);
117
/** Create a timer instance in the specified clock */
118
create(clock: TimerMap): Timer;
119
}
120
```
121
122
**Usage Examples:**
123
124
```typescript
125
import { TimerType, Clock } from "@milkdown/ctx";
126
127
// Create timer types with different timeouts
128
const quickTimer = new TimerType("quick-task", 1000);
129
const normalTimer = new TimerType("normal-task", 5000);
130
const longTimer = new TimerType("long-task", 30000);
131
132
const clock = new Clock();
133
134
// Create timer instances
135
const quick = quickTimer.create(clock.store);
136
const normal = normalTimer.create(clock.store);
137
const long = longTimer.create(clock.store);
138
139
console.log("Quick timer timeout:", quick.type.timeout); // 1000
140
console.log("Normal timer timeout:", normal.type.timeout); // 5000
141
console.log("Long timer timeout:", long.type.timeout); // 30000
142
```
143
144
### createTimer Function
145
146
Factory function for creating TimerType instances with cleaner syntax.
147
148
```typescript { .api }
149
/**
150
* Factory function for creating TimerType instances
151
* @param name - Unique name for the timer
152
* @param timeout - Timeout duration in milliseconds (default 3000)
153
* @returns New TimerType instance
154
*/
155
function createTimer(name: string, timeout?: number): TimerType;
156
```
157
158
**Usage Examples:**
159
160
```typescript
161
import { createTimer, Clock } from "@milkdown/ctx";
162
163
// Create various timer types
164
const authTimer = createTimer("authentication", 5000);
165
const apiTimer = createTimer("api-request", 10000);
166
const renderTimer = createTimer("render-complete", 2000);
167
const defaultTimer = createTimer("default-task"); // Uses 3000ms default
168
169
const clock = new Clock();
170
171
// Use in coordination scenarios
172
const timers = [authTimer, apiTimer, renderTimer].map(type =>
173
type.create(clock.store)
174
);
175
176
// Start all timers
177
const promises = timers.map(timer => timer.start());
178
179
// Simulate completion in sequence
180
setTimeout(() => timers[0].done(), 1000); // auth completes
181
setTimeout(() => timers[1].done(), 2000); // api completes
182
setTimeout(() => timers[2].done(), 3000); // render completes
183
184
Promise.all(promises).then(() => {
185
console.log("All operations completed!");
186
});
187
```
188
189
## Advanced Timer Patterns
190
191
### Sequential Timer Coordination
192
193
```typescript
194
import { Clock, createTimer } from "@milkdown/ctx";
195
196
async function sequentialTasks() {
197
const clock = new Clock();
198
199
const tasks = [
200
createTimer("load-config", 2000),
201
createTimer("init-database", 3000),
202
createTimer("start-server", 1000)
203
];
204
205
// Create all timers
206
const timers = tasks.map(task => task.create(clock.store));
207
208
// Execute sequentially
209
for (let i = 0; i < timers.length; i++) {
210
const timer = timers[i];
211
const promise = timer.start();
212
213
// Simulate task completion
214
setTimeout(() => timer.done(), 500 * (i + 1));
215
216
await promise;
217
console.log(`Task ${timer.type.name} completed`);
218
}
219
220
console.log("All tasks completed sequentially");
221
}
222
```
223
224
### Parallel Timer Coordination with Timeout Handling
225
226
```typescript
227
import { Clock, createTimer } from "@milkdown/ctx";
228
229
async function parallelTasksWithTimeouts() {
230
const clock = new Clock();
231
232
const tasks = [
233
createTimer("fast-task", 1000),
234
createTimer("medium-task", 3000),
235
createTimer("slow-task", 5000)
236
];
237
238
const timers = tasks.map(task => task.create(clock.store));
239
const promises = timers.map(timer => timer.start());
240
241
// Simulate different completion times
242
setTimeout(() => timers[0].done(), 500); // fast completes
243
setTimeout(() => timers[1].done(), 2500); // medium completes
244
// slow task will timeout (no done() call)
245
246
// Handle mixed success/timeout results
247
const results = await Promise.allSettled(promises);
248
249
results.forEach((result, index) => {
250
const timerName = timers[index].type.name;
251
if (result.status === 'fulfilled') {
252
console.log(`${timerName} completed successfully`);
253
} else {
254
console.log(`${timerName} timed out:`, result.reason.message);
255
}
256
});
257
}
258
```
259
260
### Timer-Based State Machine
261
262
```typescript
263
import { Clock, createTimer, Container, createSlice } from "@milkdown/ctx";
264
265
type AppState = 'initializing' | 'loading' | 'ready' | 'error';
266
267
class AppStateMachine {
268
private clock = new Clock();
269
private container = new Container();
270
private stateSlice = createSlice<AppState>('initializing', 'app-state');
271
272
constructor() {
273
this.stateSlice.create(this.container.sliceMap);
274
}
275
276
async initialize() {
277
const initTimer = createTimer("initialize", 2000);
278
const timer = initTimer.create(this.clock.store);
279
280
const stateSlice = this.container.get(this.stateSlice);
281
stateSlice.set('initializing');
282
283
// Start initialization
284
const promise = timer.start();
285
286
try {
287
// Simulate initialization work
288
setTimeout(() => {
289
stateSlice.set('loading');
290
timer.done();
291
}, 1000);
292
293
await promise;
294
stateSlice.set('ready');
295
console.log("App initialized successfully");
296
297
} catch (error) {
298
stateSlice.set('error');
299
console.error("Initialization failed:", error);
300
}
301
}
302
303
getState(): AppState {
304
return this.container.get(this.stateSlice);
305
}
306
}
307
```
308
309
## Types
310
311
```typescript { .api }
312
/** Internal type for the clock's timer storage */
313
type TimerMap = Map<symbol, Timer>;
314
315
/** Timer status enumeration */
316
type TimerStatus = 'pending' | 'resolved' | 'rejected';
317
```
318
319
## Error Handling
320
321
The timer system throws specific errors from `@milkdown/exception`:
322
323
- **timerNotFound**: Thrown when attempting to get a timer that doesn't exist in the clock
324
- **Timer timeout**: When timers exceed their timeout duration, promises reject with timeout error
325
326
```typescript
327
import { Clock, createTimer } from "@milkdown/ctx";
328
329
const clock = new Clock();
330
const timer = createTimer("test-timer", 1000);
331
332
try {
333
// This will throw timerNotFound
334
clock.get(timer);
335
} catch (error) {
336
console.error("Timer not found:", error.message);
337
}
338
339
// Timer timeout handling
340
const timeoutTimer = createTimer("timeout-test", 1000);
341
const timerInstance = timeoutTimer.create(clock.store);
342
343
timerInstance.start().catch((error) => {
344
console.error("Timer timed out:", error.message);
345
// Error: "Timing timeout-test timeout."
346
});
347
348
// Don't call timerInstance.done() - let it timeout
349
```
350
351
## Event System Integration
352
353
Timers use the browser's event system for coordination:
354
355
```typescript
356
import { createTimer, Clock } from "@milkdown/ctx";
357
358
const clock = new Clock();
359
const eventTimer = createTimer("custom-event", 5000);
360
const timer = eventTimer.create(clock.store);
361
362
// Listen for timer events directly (advanced usage)
363
addEventListener("custom-event", (event) => {
364
if (event instanceof CustomEvent) {
365
console.log("Timer event received:", event.detail);
366
}
367
});
368
369
// Start timer
370
timer.start().then(() => {
371
console.log("Timer completed via event system");
372
});
373
374
// Resolve timer (triggers custom event)
375
setTimeout(() => timer.done(), 2000);
376
```