diff --git a/.changeset/popular-walls-fetch.md b/.changeset/popular-walls-fetch.md new file mode 100644 index 000000000000..68e1b6d42e15 --- /dev/null +++ b/.changeset/popular-walls-fetch.md @@ -0,0 +1,5 @@ +--- +'svelte': minor +--- + +feat: pass AbortSignal to effects and allow async signature diff --git a/packages/svelte/src/ambient.d.ts b/packages/svelte/src/ambient.d.ts index 4e98eb82eb9b..87ba0a70a671 100644 --- a/packages/svelte/src/ambient.d.ts +++ b/packages/svelte/src/ambient.d.ts @@ -234,7 +234,9 @@ declare namespace $derived { * https://svelte.dev/docs/svelte/$effect * @param fn The function to execute */ -declare function $effect(fn: () => void | (() => void)): void; +declare function $effect( + fn: (input: { signal: AbortSignal }) => void | (() => void) | Promise +): void; declare namespace $effect { /** @@ -253,7 +255,9 @@ declare namespace $effect { * https://svelte.dev/docs/svelte/$effect#$effect.pre * @param fn The function to execute */ - export function pre(fn: () => void | (() => void)): void; + export function pre( + fn: (input: { signal: AbortSignal }) => void | (() => void) | Promise + ): void; /** * The `$effect.tracking` rune is an advanced feature that tells you whether or not the code is running inside a tracking context, such as an effect or inside your template. diff --git a/packages/svelte/src/internal/client/runtime.js b/packages/svelte/src/internal/client/runtime.js index 4aa3d17a15e8..64cabcf35636 100644 --- a/packages/svelte/src/internal/client/runtime.js +++ b/packages/svelte/src/internal/client/runtime.js @@ -398,7 +398,22 @@ export function update_reaction(reaction) { component_context = reaction.ctx; try { - var result = /** @type {Function} */ (0, reaction.fn)(); + /** @type {any} */ + var result; + + if ((flags & EFFECT) !== 0 && /** @type {Function} */ (reaction.fn).length > 0) { + var controller = new AbortController(); + var signal = controller.signal; + var inner = /** @type {Function} */ (0, reaction.fn)({ signal }); + + result = () => { + controller.abort('effect destroyed'); + inner?.(); + }; + } else { + result = /** @type {Function} */ (0, reaction.fn)(); + } + var deps = reaction.deps; if (new_deps !== null) { diff --git a/packages/svelte/types/index.d.ts b/packages/svelte/types/index.d.ts index 671f68bff72a..c3b8a41eb912 100644 --- a/packages/svelte/types/index.d.ts +++ b/packages/svelte/types/index.d.ts @@ -2892,7 +2892,9 @@ declare namespace $derived { * https://svelte.dev/docs/svelte/$effect * @param fn The function to execute */ -declare function $effect(fn: () => void | (() => void)): void; +declare function $effect( + fn: (input: { signal: AbortSignal }) => void | (() => void) | Promise +): void; declare namespace $effect { /** @@ -2911,7 +2913,9 @@ declare namespace $effect { * https://svelte.dev/docs/svelte/$effect#$effect.pre * @param fn The function to execute */ - export function pre(fn: () => void | (() => void)): void; + export function pre( + fn: (input: { signal: AbortSignal }) => void | (() => void) | Promise + ): void; /** * The `$effect.tracking` rune is an advanced feature that tells you whether or not the code is running inside a tracking context, such as an effect or inside your template.