Skip to content

Commit bfd4be5

Browse files
committed
fix: ensure effect queue is properly cleaned up after flush error
close #97
1 parent 6f8f8d3 commit bfd4be5

File tree

2 files changed

+56
-7
lines changed

2 files changed

+56
-7
lines changed

src/index.ts

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ const {
4040
let firstInsertedIndex = insertIndex;
4141

4242
do {
43-
effect.flags &= ~ReactiveFlags.Watching;
4443
queued[insertIndex++] = effect;
44+
effect.flags &= ~ReactiveFlags.Watching;
4545
effect = effect.subs?.sub as EffectNode;
4646
if (effect === undefined || !(effect.flags & ReactiveFlags.Watching)) {
4747
break;
@@ -256,13 +256,21 @@ function run(e: EffectNode): void {
256256
}
257257

258258
function flush(): void {
259-
while (notifyIndex < queuedLength) {
260-
const effect = queued[notifyIndex]!;
261-
queued[notifyIndex++] = undefined;
262-
run(effect);
259+
try {
260+
while (notifyIndex < queuedLength) {
261+
const effect = queued[notifyIndex]!;
262+
queued[notifyIndex++] = undefined;
263+
run(effect);
264+
}
265+
} finally {
266+
while (notifyIndex < queuedLength) {
267+
const effect = queued[notifyIndex]!;
268+
queued[notifyIndex++] = undefined;
269+
effect.flags |= ReactiveFlags.Watching | ReactiveFlags.Recursed;
270+
}
271+
notifyIndex = 0;
272+
queuedLength = 0;
263273
}
264-
notifyIndex = 0;
265-
queuedLength = 0;
266274
}
267275

268276
function computedOper<T>(this: ComputedNode<T>): T {

tests/effect.spec.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,3 +286,44 @@ test('should support custom recurse effect', () => {
286286

287287
expect(triggers).toBe(6);
288288
});
289+
290+
test('should not execute skipped effects from previous failed flush when updating unrelated signal', () => {
291+
const a = signal(0);
292+
const b = signal(0);
293+
const c = signal(0);
294+
const d = computed(() => (c(), 0));
295+
296+
let effect3Executed = false;
297+
298+
effect(() => {
299+
a();
300+
});
301+
effect(() => {
302+
if (a() === 2) {
303+
throw new Error('Error in effect 2');
304+
}
305+
});
306+
effect(() => {
307+
a();
308+
d();
309+
effect3Executed = true;
310+
});
311+
effect(() => {
312+
b();
313+
});
314+
315+
a(1);
316+
317+
effect3Executed = false;
318+
try {
319+
a(2);
320+
} catch (e) {
321+
expect((e as Error).message).toBe('Error in effect 2');
322+
}
323+
324+
expect(effect3Executed).toBe(false);
325+
b(1);
326+
expect(effect3Executed).toBe(false);
327+
c(1);
328+
expect(effect3Executed).toBe(true);
329+
});

0 commit comments

Comments
 (0)