Skip to content

Commit

Permalink
Fix problems in PerformanceObserver notifications (facebook#43847)
Browse files Browse the repository at this point in the history
Summary:

Changelog: [internal]

(This is an internal change because the API hasn't been released in OSS yet)

This fixes 2 problems in how we dispatch `PerformanceObserver` notifications:
1. If an observer callback throws an error, the remaining observers don't receive notifications.
2. We're notifying observers with an empty list of events when they don't match the filters.

Differential Revision: D55646390
  • Loading branch information
rubennorte authored and facebook-github-bot committed Apr 4, 2024
1 parent dc83cb7 commit 74ea8bc
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,17 @@ const onPerformanceEntry = () => {
const durationThreshold = observerConfig.entryTypes.get(entry.entryType);
return entry.duration >= (durationThreshold ?? 0);
});
observerConfig.callback(
new PerformanceObserverEntryList(entriesForObserver),
observer,
droppedEntriesCount,
);
if (entriesForObserver.length !== 0) {
try {
observerConfig.callback(
new PerformanceObserverEntryList(entriesForObserver),
observer,
droppedEntriesCount,
);
} catch (error) {
console.error(error);
}
}
}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,4 +205,58 @@ describe('PerformanceObserver', () => {
'mark7',
]);
});

it('should guard against errors in observer callbacks', () => {
jest.spyOn(console, 'error').mockImplementation(() => {});

const observer1Callback = jest.fn(() => {
throw new Error('observer 1 callback');
});
const observer1 = new PerformanceObserver(observer1Callback);

const observer2Callback = jest.fn();
const observer2 = new PerformanceObserver(observer2Callback);

observer1.observe({type: 'mark'});
observer2.observe({type: 'mark'});

NativePerformanceObserver.logRawEntry({
name: 'mark1',
entryType: RawPerformanceEntryTypeValues.MARK,
startTime: 0,
duration: 200,
});

jest.runAllTicks();

expect(observer1Callback).toHaveBeenCalled();
expect(observer2Callback).toHaveBeenCalled();

expect(console.error).toHaveBeenCalledWith(
new Error('observer 1 callback'),
);
});

it('should not invoke observers with non-matching entries', () => {
const observer1Callback = jest.fn();
const observer1 = new PerformanceObserver(observer1Callback);

const observer2Callback = jest.fn();
const observer2 = new PerformanceObserver(observer2Callback);

observer1.observe({type: 'mark'});
observer2.observe({type: 'measure'});

NativePerformanceObserver.logRawEntry({
name: 'mark1',
entryType: RawPerformanceEntryTypeValues.MARK,
startTime: 0,
duration: 200,
});

jest.runAllTicks();

expect(observer1Callback).toHaveBeenCalled();
expect(observer2Callback).not.toHaveBeenCalled();
});
});

0 comments on commit 74ea8bc

Please sign in to comment.