diff --git a/packages/svelte/src/ambient.d.ts b/packages/svelte/src/ambient.d.ts index e9dbf502bf..0ad52d4b37 100644 --- a/packages/svelte/src/ambient.d.ts +++ b/packages/svelte/src/ambient.d.ts @@ -234,7 +234,7 @@ declare namespace $derived { * https://svelte.dev/docs/svelte/$effect * @param fn The function to execute */ -declare function $effect(fn: () => void | (() => void) | AbortController): void; +declare function $effect(fn: (signal: AbortSignal) => void | ((signal: AbortSignal) => void)): void; declare namespace $effect { /** @@ -253,7 +253,7 @@ declare namespace $effect { * https://svelte.dev/docs/svelte/$effect#$effect.pre * @param fn The function to execute */ - export function pre(fn: () => void | (() => void) | AbortController): void; + export function pre(fn: (signal: AbortSignal) => void | ((signal: AbortSignal) => void)): 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 101d0e9742..86d4e21cba 100644 --- a/packages/svelte/src/internal/client/runtime.js +++ b/packages/svelte/src/internal/client/runtime.js @@ -1,6 +1,6 @@ /** @import { ComponentContext, Derived, Effect, Reaction, Signal, Source, Value } from '#client' */ import { DEV } from 'esm-env'; -import { define_property, get_descriptors, get_prototype_of } from '../shared/utils.js'; +import { define_property, get_descriptors, get_prototype_of, run_all } from '../shared/utils.js'; import { destroy_block_effect_children, destroy_effect_children, @@ -398,7 +398,21 @@ 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 inner = /** @type {Function} */ (0, reaction.fn)(controller.signal); + + result = () => { + controller.abort('effect destroyed'); + inner?.(); + } + } else { + result = /** @type {Function} */ (0, reaction.fn)(); + } + var deps = reaction.deps; if (new_deps !== null) { @@ -524,12 +538,8 @@ export function update_effect(effect) { destroy_effect_deriveds(effect); execute_effect_teardown(effect); - var teardown = update_reaction(effect) ?? null; - // Avoid doing an instanceof check on the hot-path - effect.teardown = - teardown === null || typeof teardown === 'function' || teardown instanceof AbortController - ? teardown - : null; + var teardown = update_reaction(effect); + effect.teardown = typeof teardown === 'function' ? teardown : null; effect.version = current_version; if (DEV) { diff --git a/packages/svelte/types/index.d.ts b/packages/svelte/types/index.d.ts index 9ef55d766f..25de0d7026 100644 --- a/packages/svelte/types/index.d.ts +++ b/packages/svelte/types/index.d.ts @@ -2892,7 +2892,7 @@ declare namespace $derived { * https://svelte.dev/docs/svelte/$effect * @param fn The function to execute */ -declare function $effect(fn: () => void | (() => void) | AbortController): void; +declare function $effect(fn: (signal: AbortSignal) => void | ((signal: AbortSignal) => void)): void; declare namespace $effect { /** @@ -2911,7 +2911,7 @@ declare namespace $effect { * https://svelte.dev/docs/svelte/$effect#$effect.pre * @param fn The function to execute */ - export function pre(fn: () => void | (() => void) | AbortController): void; + export function pre(fn: (signal: AbortSignal) => void | ((signal: AbortSignal) => void)): 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.