Skip to content

Commit a9fc5e8

Browse files
authored
feat: add new activeLoops getter (#1)
1 parent 582e5f5 commit a9fc5e8

File tree

3 files changed

+30
-4
lines changed

3 files changed

+30
-4
lines changed

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
- API-Friendly
3131

3232
<blockquote>
33-
<sub><strong>Package size</strong>: <code>~1.44 KB</code> minified, <code>~790 B</code> gzip</sub>
33+
<sub><strong>Package size</strong>: <code>~1.54 KB</code> minified, <code>~855 B</code> gzip</sub>
3434
</blockquote>
3535

3636
## Core Concepts
@@ -230,6 +230,9 @@ By default, the callback will only be executed once.
230230

231231
```ts
232232
frame.update((state) => console.log(state), { loop: true })
233+
234+
// The number of active frame loops can also be accessed via the `.activeLoops` getter
235+
console.log(frame.activeLoops)
233236
```
234237

235238
### schedule

src/index.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,9 @@ export function createFrame<T extends string = PhaseIDs>(
9292
} = options
9393

9494
const phases = {} as Record<T, Phase>
95-
const loops = new Set<PhaseCallback>()
95+
96+
let loops = new WeakSet<PhaseCallback>()
97+
let activeLoops: number = 0
9698

9799
let tickerId: number | null = null
98100
let shouldRunTicker: boolean = false
@@ -129,7 +131,10 @@ export function createFrame<T extends string = PhaseIDs>(
129131
{ loop, schedule = true }: PhaseScheduleOptions = {},
130132
): PhaseCallback => {
131133
const queue = isRunning && !schedule ? thisFrame : nextFrame
132-
if (loop) loops.add(callback)
134+
if (loop) {
135+
if (!loops.has(callback)) activeLoops++
136+
loops.add(callback)
137+
}
133138
if (!queue.has(callback)) queue.add(callback)
134139
return callback
135140
},
@@ -154,6 +159,7 @@ export function createFrame<T extends string = PhaseIDs>(
154159
},
155160
cancel: (callback: PhaseCallback): void => {
156161
nextFrame.delete(callback)
162+
if (loops.has(callback)) activeLoops--
157163
loops.delete(callback)
158164
},
159165
clear: (): void => {
@@ -198,7 +204,7 @@ export function createFrame<T extends string = PhaseIDs>(
198204
const now = performance.now()
199205
const time = now - totalPausedTime
200206

201-
shouldRunTicker = loops.size > 0
207+
shouldRunTicker = activeLoops > 0
202208

203209
if (fps) {
204210
const delta = time - lastFrameTime
@@ -255,13 +261,18 @@ export function createFrame<T extends string = PhaseIDs>(
255261
},
256262
clear: (): void => {
257263
state = defaultState()
264+
loops = new WeakSet()
265+
activeLoops = 0
258266
phase((id) => id.clear())
259267
cancelTicker()
260268
shouldRunTicker = false
261269
},
262270
get state(): Readonly<FrameState> {
263271
return state
264272
},
273+
get activeLoops(): Readonly<number> {
274+
return activeLoops
275+
},
265276
} as Frame<T>
266277

267278
framePhases.forEach((id) => {

src/types.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,18 @@ export type Frame<T extends string> = {
136136
* ```
137137
*/
138138
get state(): Readonly<FrameState>
139+
/**
140+
* Provides a read-only number of active frame loops at any given point.
141+
*
142+
* Useful for debugging and monitoring or for dynamic actions.
143+
*
144+
* @example
145+
*
146+
* ```ts
147+
* frame.activeLoops
148+
* ```
149+
*/
150+
get activeLoops(): Readonly<number>
139151
} & FramePhases<T>
140152

141153
export type TickerIDs = 'raf' | 'timeout'

0 commit comments

Comments
 (0)