What Is the Typical Time Slicing Threshold in Fre's Concurrent Mode?
Fre's concurrent mode uses a fixed 5 ms time-slicing threshold to determine when to yield control back to the browser, ensuring UI responsiveness during heavy computation.
The Fre library (frejs/fre) implements a cooperative scheduling system inspired by React's concurrent features. At the heart of this system lies a hardcoded time-slicing threshold that dictates how long the scheduler can monopolize the main thread before yielding to the browser's event loop.
Where the 5 ms Threshold Is Defined
In src/schedule.ts, the threshold is exported as a constant:
const threshold: number = 5
This value represents milliseconds. The scheduler references this constant when initiating a new batch of work, calculating a deadline by adding the threshold to the current high-resolution timestamp.
How the Scheduler Uses the Threshold
When work begins, the scheduler establishes a deadline in src/schedule.ts:
deadline = getTime() + threshold
The getTime() function typically wraps performance.now(). As the scheduler processes tasks in a loop, it continuously checks shouldYield(), which returns true once performance.now() >= deadline. At this point, the scheduler pauses execution and schedules the remaining work for a subsequent frame using a microtask, MessageChannel, or setTimeout fallback.
Why 5 ms? Balancing Throughput and Responsiveness
The 5 ms slice represents a compromise between two competing priorities:
- Responsiveness: Keeping slices below the 16 ms frame budget (60 fps) ensures the browser can handle user input, layout, and paint operations without jank.
- Throughput: A 5 ms window allows sufficient work to complete per slice, reducing the overhead of context switching and callback scheduling.
This value aligns with similar concurrent schedulers in the React ecosystem, providing predictable performance characteristics across devices.
Working with the Time Slice in Practice
Scheduling Heavy Computations
When breaking intensive work into chunks:
import { schedule } from 'fre'
function processLargeDataset(index = 0) {
const chunkSize = 100
const end = Math.min(index + chunkSize, data.length)
for (let i = index; i < end; i++) {
processItem(data[i])
}
// Continue if work remains
return end < data.length ? () => processLargeDataset(end) : undefined
}
schedule(processLargeDataset)
Monitoring Yield Points
To observe when the scheduler yields:
import { schedule, shouldYield } from 'fre'
let sliceCount = 0
schedule(() => {
while (!shouldYield()) {
// Perform work
performUnitOfWork()
}
sliceCount++
console.log(`Yielded after slice ${sliceCount} at ${performance.now()}ms`)
// Return function to continue, or undefined to stop
return hasMoreWork ? () => continueWork() : undefined
})
Summary
- Fre's concurrent scheduler hardcodes a 5 ms time-slicing threshold in
src/schedule.ts. - The scheduler calculates a deadline using
performance.now() + 5at the start of each work phase. - Work continues until
shouldYield()detects the deadline has passed, at which point control returns to the browser. - This 5 ms balance optimizes for both 60 fps responsiveness and efficient task throughput.
Frequently Asked Questions
Why does Fre use a 5 ms threshold instead of a longer time slice?
Fre uses 5 ms to maintain compatibility with the browser's frame budget. At 60 frames per second, each frame has approximately 16.6 ms available. By yielding after 5 ms, Fre ensures sufficient time remains for the browser to handle layout, paint, and user input events, preventing interface jank while still making meaningful progress on background tasks.
How can I monitor if my tasks are exceeding the time slice?
You can import shouldYield from fre and check its return value within your work loop. When shouldYield() returns true, the scheduler has exceeded the 5 ms deadline and will pause execution. Logging timestamps at these yield points allows you to measure actual slice duration and identify tasks that consistently overrun the threshold, indicating they need further decomposition.
Does the threshold change based on device performance?
No, the threshold is a hardcoded constant (const threshold: number = 5) in src/schedule.ts. Unlike some adaptive schedulers that dynamically adjust time slices based on device capabilities or battery status, Fre uses a fixed 5 ms value across all environments. This provides predictable, deterministic behavior but means developers must ensure their work units fit within this universal constraint.
Can I configure the time-slicing threshold in Fre?
Currently, Fre does not expose a public API to modify the threshold. The constant is defined internally in the scheduler module and is not exported or accepted as a configuration parameter. If you require different timing characteristics for specialized use cases, you would need to fork the repository and modify the threshold value in src/schedule.ts directly, though this deviates from the standard library behavior.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →