Skip to content

Commit 548ad7b

Browse files
fix: wrap abort in without_reactive_context (#16570)
* fix: wrap `abort` in `without_reactive_context` * only call without_reactive_context when the controller exists --------- Co-authored-by: Rich Harris <[email protected]>
1 parent 97f263c commit 548ad7b

File tree

5 files changed

+54
-2
lines changed

5 files changed

+54
-2
lines changed

.changeset/khaki-feet-teach.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: wrap `abort` in `without_reactive_context`

packages/svelte/src/internal/client/reactivity/effects.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import { get_next_sibling } from '../dom/operations.js';
4242
import { component_context, dev_current_component_function, dev_stack } from '../context.js';
4343
import { Batch, schedule_effect } from './batch.js';
4444
import { flatten } from './async.js';
45+
import { without_reactive_context } from '../dom/elements/bindings/shared.js';
4546

4647
/**
4748
* @param {'$effect' | '$effect.pre' | '$inspect'} rune
@@ -406,7 +407,13 @@ export function destroy_effect_children(signal, remove_dom = false) {
406407
signal.first = signal.last = null;
407408

408409
while (effect !== null) {
409-
effect.ac?.abort(STALE_REACTION);
410+
const controller = effect.ac;
411+
412+
if (controller !== null) {
413+
without_reactive_context(() => {
414+
controller.abort(STALE_REACTION);
415+
});
416+
}
410417

411418
var next = effect.next;
412419

packages/svelte/src/internal/client/runtime.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ import { Batch, batch_deriveds, flushSync, schedule_effect } from './reactivity/
4646
import { handle_error } from './error-handling.js';
4747
import { UNINITIALIZED } from '../../constants.js';
4848
import { captured_signals } from './legacy.js';
49+
import { without_reactive_context } from './dom/elements/bindings/shared.js';
4950

5051
export let is_updating_effect = false;
5152

@@ -278,7 +279,10 @@ export function update_reaction(reaction) {
278279
update_version = ++read_version;
279280

280281
if (reaction.ac !== null) {
281-
reaction.ac.abort(STALE_REACTION);
282+
without_reactive_context(() => {
283+
/** @type {AbortController} */ (reaction.ac).abort(STALE_REACTION);
284+
});
285+
282286
reaction.ac = null;
283287
}
284288

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { ok, test } from '../../test';
2+
import { flushSync } from 'svelte';
3+
4+
export default test({
5+
async test({ assert, target, errors }) {
6+
const btn = target.querySelector('button');
7+
flushSync(() => {
8+
btn?.click();
9+
});
10+
assert.deepEqual(errors, []);
11+
}
12+
});
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<script lang="ts">
2+
import { getAbortSignal } from "svelte";
3+
4+
let aborted = $state(0);
5+
6+
let count = $state(0);
7+
8+
let der = $derived.by(()=>{
9+
const signal = getAbortSignal();
10+
11+
signal.addEventListener("abort", () => {
12+
try{
13+
aborted++;
14+
}catch(e){
15+
console.error(e);
16+
}
17+
});
18+
return count;
19+
})
20+
</script>
21+
22+
{der}
23+
24+
<button onclick={() => count++}></button>

0 commit comments

Comments
 (0)