Dispatcher & Fiber Management
Relevant source files
The following files were used as context for generating this wiki page:
- modules/svelte-effect-runtime/src/dispatcher/index.ts
- modules/svelte-effect-runtime/src/dispatcher/types.ts
- modules/svelte-effect-runtime/src/script-transform/index.ts
- modules/svelte-effect-runtime/src/compiler/source-scan.ts
- modules/svelte-effect-runtime/src/diagnostics.ts
- modules/svelte-effect-runtime/src/markup/transform/index.ts
The Dispatcher and Fiber management system serves as the core orchestration layer in the Svelte Effect Runtime (SER). It is responsible for bridging the gap between Svelte's reactive lifecycle and the Effect library's fiber-based execution model. The Dispatcher manages the creation, cancellation, and caching of Effect fibers, ensuring that effectful operations (like data fetching or event handling) are correctly synchronized with Svelte component updates and unmounting.
At a high level, the system intercepts generated code from the Script Transform and Markup Transform phases to execute effects through a managed runtime. It handles reactive dependencies by automatically interrupting stale fibers when dependency arrays change, and it wires execution results into Svelte's $state or promises.
Sources: modules/svelte-effect-runtime/src/dispatcher/index.ts:39-50, modules/svelte-effect-runtime/src/script-transform/index.ts:33-46
Architecture Overview
The architecture centers on the Dispatcher class, which maintains an internal ManagedRuntime from the Effect library. It acts as a singleton manager for all fibers spawned within a Svelte context.
The Dispatcher Class
The Dispatcher keeps track of active fibers, cached values, and Svelte subscribers. It uses a series of internal maps to manage state:
#fibers: A map of activeFiberinstances keyed by unique block IDs or generated fork IDs.#value_cells: A cache for reactive values, storing the status (pending,success, orfailure) and the associated data or fiber.#promise_values: A cache for promise-based effect results.
Sources: modules/svelte-effect-runtime/src/dispatcher/index.ts:51-85
Fiber Lifecycle Flow
When an effect is emitted via the dispatcher, it follows a strict lifecycle of dependency hashing, fiber forking, and reactive notification.
The diagram shows how the Dispatcher handles different event types and manages the transition from a Svelte event to a managed Effect fiber.
Sources: modules/svelte-effect-runtime/src/dispatcher/index.ts:133-146, modules/svelte-effect-runtime/src/dispatcher/index.ts:333-360
Fiber Management and Caching
The system provides sophisticated management of fibers to prevent memory leaks and ensure reactive consistency.
Dependency Tracking
The value and promise methods use a cache key generated from a stable block ID and a hash of the provided dependencies. If a new request arrives with the same ID but different dependencies, the system automatically interrupts the existing fiber for that ID before starting a new one.
| Method | Purpose | Cleanup Behavior |
|---|---|---|
fork | Manual execution | Returns a Dispose function to interrupt. |
value | Reactive state binding | Auto-interrupts on dependency change; notifies Svelte. |
promise | Async/await integration | Auto-interrupts on dependency change; rejects stale promises. |
run | Event handlers | Executes immediately; surfaces errors to Svelte. |
Sources: modules/svelte-effect-runtime/src/dispatcher/index.ts:161-267, modules/svelte-effect-runtime/src/dispatcher/index.ts:311-331
Value Cells
Value cells represent the state of an effect forked into Svelte's reactive system. They are managed through a ValueCell type.
type ValueCell<A> =
| { readonly status: "pending"; readonly fiber: FiberType<unknown, unknown>; }
| { readonly status: "success"; readonly value: A; }
| { readonly status: "failure"; readonly error: unknown; };
Sources: modules/svelte-effect-runtime/src/dispatcher/index.ts:25-37
Integration with Svelte Transforms
The Dispatcher does not operate in isolation; it is the target for transformations performed on Svelte source code.
Script Lowering and Event Emission
During script transformation, top-level yield* expressions are rewritten into calls to the Dispatcher. The transform identifies the need for a dispatcher and injects the necessary imports.
The sequence diagram illustrates the transition from build-time transformation to runtime fiber execution.
Sources: modules/svelte-effect-runtime/src/script-transform/index.ts:48-120, modules/svelte-effect-runtime/src/dispatcher/index.ts:121-149
Markup Integration
The markup transformer identifies yield* inside brace expressions (e.g., in attributes or #each blocks) and replaces them with placeholders that eventually call dispatcher.emit.
- File Path:
modules/svelte-effect-runtime/src/markup/transform/index.ts - Key Logic: Uses
sanitize_markupto find candidates, then matches them to Svelte AST contexts to determine if the effect should be treated as a value, promise, or handler.
Sources: modules/svelte-effect-runtime/src/markup/transform/index.ts:55-100, modules/svelte-effect-runtime/src/compiler/source-scan.ts:404-436
Diagnostics and Safety
To ensure fibers are managed correctly, the system includes a diagnostic scanner that detects "unmanaged" effects—effects created within markup or handlers but not passed through the yield* keyword.
| Diagnostic Check | Warning Message | Logic |
|---|---|---|
| Explicit Runners | "Detected an explicit Effect runner" | Detects manual calls to Effect.runPromise/Fork. |
Bare Effect.gen | "Detected Effect.gen used as a value" | Ensures constructors are executed, not just referenced. |
| Hidden Yields | "Detected yield* hidden inside callback" | Prevents onclick={() => yield* effect}. |
Sources: modules/svelte-effect-runtime/src/diagnostics.ts:90-145
Disposal and Resource Cleanup
The Dispatcher implements a dispose method that is critical for component unmounting and HMR (Hot Module Replacement).
dispose(): void {
this.#disposed = true;
for (const fiber of this.#fibers.values()) {
interrupt_fiber(this.#runtime, fiber);
}
this.#fibers.clear();
this.#clear_value_cells();
this.#runtime.dispose();
}
Calling dispose sets an internal #disposed flag that prevents any new work from starting and immediately interrupts all active fibers currently tracked in the #fibers map.
Sources: modules/svelte-effect-runtime/src/dispatcher/index.ts:275-305
Summary
The Dispatcher and Fiber Management system provides a robust infrastructure for executing Effect programs within Svelte components. By combining build-time transformations with a reactive runtime manager, SER ensures that async effects respect Svelte's lifecycle, dependencies are tracked correctly, and resources are leaked neither during normal operation nor during unmounting.