FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

fix(core): keep running sibling root effects after one throws by erkamyaman · Pull Request #71154 · angular/angular · GitHub

Repository navigation

Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension .ts  (2) All 1 file type selected
Viewed files
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Unified
Split
Hide whitespace
Diff view
Unified
Split
Hide whitespace
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
* found in the LICENSE file at https://angular.dev/license
*/

import {inject} from '../../di/injector_compatibility';
import {ɵɵdefineInjectable} from '../../di/interface/defs';
import {INTERNAL_APPLICATION_ERROR_HANDLER} from '../../error_handler';

/**
* Abstraction that encompasses any kind of effect that can be scheduled.
Expand Down Expand Up @@ -55,6 +57,7 @@ export abstract class EffectScheduler {
export class ZoneAwareEffectScheduler implements EffectScheduler {
private dirtyEffectCount = 0;
private queues = new Map<Zone | null, Set<SchedulableEffect>>();
private readonly errorHandler = inject(INTERNAL_APPLICATION_ERROR_HANDLER);

add(handle: SchedulableEffect): void {
this.enqueue(handle);
Expand Down Expand Up @@ -129,8 +132,13 @@ export class ZoneAwareEffectScheduler implements EffectScheduler {
this.dirtyEffectCount--;
ranOneEffect = true;

// TODO: what happens if this throws an error?
handle.run();
// An effect that throws must not prevent the remaining scheduled effects from running,
// so report the error and continue flushing the queue.
try {
handle.run();
} catch (e) {
this.errorHandler(e);
}
}
return ranOneEffect;
}
Expand Down
52 changes: 52 additions & 0 deletions packages/core/test/render3/reactivity_spec.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,58 @@ describe('reactivity', () => {
expect(lastError.message).toBe('fail!');
});

it('should keep running sibling root effects after one throws', async () => {
TestBed.configureTestingModule({
providers: [{provide: ErrorHandler, useFactory: () => new FakeErrorHandler()}],
rethrowApplicationErrors: false,
});

let lastError: any = null;
class FakeErrorHandler extends ErrorHandler {
override handleError(error: any): void {
lastError = error;
}
}
const appRef = TestBed.inject(ApplicationRef);

const trigger = signal(false);
const other = signal(0);
const seen: number[] = [];

// The first-registered root effect throws once `trigger` is set.
effect(
() => {
if (trigger()) {
throw new Error('boom');
}
},
{injector: appRef.injector},
);
// A sibling root effect, registered after it, reads a different signal.
effect(
() => {
seen.push(other());
},
{injector: appRef.injector},
);

await appRef.whenStable();
expect(seen).toEqual([0]);

// In the same turn, the first effect throws and the sibling's dependency changes.
trigger.set(true);
other.set(1);
await appRef.whenStable();

expect(lastError.message).toBe('boom');
expect(seen).toEqual([0, 1]);

// The sibling must keep reacting to later changes too.
other.set(2);
await appRef.whenStable();
expect(seen).toEqual([0, 1, 2]);
});

// Disabled while we consider whether this actually makes sense.
// This test _used_ to show that `effect()` was usable inside component error handlers, partly
// because effect errors used to report to component error handlers. Now, effect errors are
Expand Down
Loading

Back | FazBrowse Home | New Git URL