From afbd927fc0e0f953e94d5a9c3791564d69192b5a Mon Sep 17 00:00:00 2001 From: egrs Date: Tue, 17 Feb 2026 15:58:38 +0100 Subject: [PATCH 1/5] support buffered option in PerformanceObserver.observe() When buffered is true, deliver existing performance entries that match the observer's interest immediately, per the Performance Observer spec. --- .../performance_observer.html | 28 +++++++++++++++++++ src/browser/webapi/PerformanceObserver.zig | 12 ++++++++ 2 files changed, 40 insertions(+) diff --git a/src/browser/tests/performance_observer/performance_observer.html b/src/browser/tests/performance_observer/performance_observer.html index 7b5b6c9e..efa90e80 100644 --- a/src/browser/tests/performance_observer/performance_observer.html +++ b/src/browser/tests/performance_observer/performance_observer.html @@ -69,3 +69,31 @@ + + diff --git a/src/browser/webapi/PerformanceObserver.zig b/src/browser/webapi/PerformanceObserver.zig index ad130c97..cd6a672e 100644 --- a/src/browser/webapi/PerformanceObserver.zig +++ b/src/browser/webapi/PerformanceObserver.zig @@ -113,6 +113,18 @@ pub fn observe( // Update interests. self._interests = interests; + + // Deliver existing entries if buffered option is set. + if (options.buffered) { + for (page.window._performance._entries.items) |entry| { + if (self.interested(entry)) { + try self._entries.append(page.arena, entry); + } + } + if (self.hasRecords()) { + try self.dispatch(page); + } + } } pub fn disconnect(self: *PerformanceObserver, page: *Page) void { From df9779ec5985ae0afed5886624620234620fff87 Mon Sep 17 00:00:00 2001 From: egrs Date: Tue, 17 Feb 2026 16:12:20 +0100 Subject: [PATCH 2/5] restrict buffered option to type-based observation per spec The buffered option is only valid with the type option, not entryTypes, per the Performance Observer specification. --- src/browser/webapi/PerformanceObserver.zig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/browser/webapi/PerformanceObserver.zig b/src/browser/webapi/PerformanceObserver.zig index cd6a672e..088128b1 100644 --- a/src/browser/webapi/PerformanceObserver.zig +++ b/src/browser/webapi/PerformanceObserver.zig @@ -115,7 +115,8 @@ pub fn observe( self._interests = interests; // Deliver existing entries if buffered option is set. - if (options.buffered) { + // Per spec, buffered is only valid with the type option, not entryTypes. + if (options.buffered and options.type != null) { for (page.window._performance._entries.items) |entry| { if (self.interested(entry)) { try self._entries.append(page.arena, entry); From ca9e2200da00f669b94e47aa00c1070b923ffa89 Mon Sep 17 00:00:00 2001 From: egrs Date: Tue, 17 Feb 2026 18:16:42 +0100 Subject: [PATCH 3/5] use async delivery for buffered performance observer entries Per spec, buffered entries should be delivered via a queued task, not synchronously. Extract scheduling logic into schedulePerformanceObserverDelivery() and use it from both notifyPerformanceObservers and the buffered observe path. --- src/browser/Page.zig | 5 +++++ src/browser/webapi/PerformanceObserver.zig | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/browser/Page.zig b/src/browser/Page.zig index 5940d2c5..c1350a0e 100644 --- a/src/browser/Page.zig +++ b/src/browser/Page.zig @@ -1243,6 +1243,11 @@ pub fn notifyPerformanceObservers(self: *Page, entry: *Performance.Entry) !void } } + try self.schedulePerformanceObserverDelivery(); +} + +/// Schedules async delivery of buffered performance observer records. +pub fn schedulePerformanceObserverDelivery(self: *Page) !void { // Already scheduled. if (self._performance_delivery_scheduled) { return; diff --git a/src/browser/webapi/PerformanceObserver.zig b/src/browser/webapi/PerformanceObserver.zig index 088128b1..38f2a028 100644 --- a/src/browser/webapi/PerformanceObserver.zig +++ b/src/browser/webapi/PerformanceObserver.zig @@ -116,6 +116,7 @@ pub fn observe( // Deliver existing entries if buffered option is set. // Per spec, buffered is only valid with the type option, not entryTypes. + // Delivery is async via a queued task, not synchronous. if (options.buffered and options.type != null) { for (page.window._performance._entries.items) |entry| { if (self.interested(entry)) { @@ -123,7 +124,7 @@ pub fn observe( } } if (self.hasRecords()) { - try self.dispatch(page); + try page.schedulePerformanceObserverDelivery(); } } } From 7c92e0e9ce7f387f1b05a98c83faeee72b8a9f98 Mon Sep 17 00:00:00 2001 From: egrs Date: Wed, 18 Feb 2026 07:14:12 +0100 Subject: [PATCH 4/5] address review: fix doc comment, skip buffered if already queued --- src/browser/Page.zig | 2 +- src/browser/webapi/PerformanceObserver.zig | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/browser/Page.zig b/src/browser/Page.zig index c1350a0e..40b73618 100644 --- a/src/browser/Page.zig +++ b/src/browser/Page.zig @@ -1246,7 +1246,7 @@ pub fn notifyPerformanceObservers(self: *Page, entry: *Performance.Entry) !void try self.schedulePerformanceObserverDelivery(); } -/// Schedules async delivery of buffered performance observer records. +/// Schedules async delivery of performance observer records. pub fn schedulePerformanceObserverDelivery(self: *Page) !void { // Already scheduled. if (self._performance_delivery_scheduled) { diff --git a/src/browser/webapi/PerformanceObserver.zig b/src/browser/webapi/PerformanceObserver.zig index 38f2a028..cfabaebb 100644 --- a/src/browser/webapi/PerformanceObserver.zig +++ b/src/browser/webapi/PerformanceObserver.zig @@ -117,7 +117,7 @@ pub fn observe( // Deliver existing entries if buffered option is set. // Per spec, buffered is only valid with the type option, not entryTypes. // Delivery is async via a queued task, not synchronous. - if (options.buffered and options.type != null) { + if (options.buffered and options.type != null and !self.hasRecords()) { for (page.window._performance._entries.items) |entry| { if (self.interested(entry)) { try self._entries.append(page.arena, entry); From f72a354066175adf28c77865f19800b0336852bd Mon Sep 17 00:00:00 2001 From: egrs Date: Wed, 18 Feb 2026 07:15:17 +0100 Subject: [PATCH 5/5] address review: clear marks before test, assert exactly 2 --- .../performance_observer/performance_observer.html | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/browser/tests/performance_observer/performance_observer.html b/src/browser/tests/performance_observer/performance_observer.html index efa90e80..a0797e15 100644 --- a/src/browser/tests/performance_observer/performance_observer.html +++ b/src/browser/tests/performance_observer/performance_observer.html @@ -72,6 +72,9 @@