From acebbb90412a02e5ee4770648b31a74bd0b813b6 Mon Sep 17 00:00:00 2001 From: Halil Durak Date: Mon, 22 Dec 2025 13:19:00 +0300 Subject: [PATCH] don't prefer microtask queue for execution This still needs investigation. Spec doesn't refer usage of microtask queue for this, yet the current behavior doesn't match to Firefox and Chrome. --- src/browser/Page.zig | 19 ++++++++++++++++--- src/browser/js/Context.zig | 10 ---------- src/browser/webapi/PerformanceObserver.zig | 17 +++++++++++++---- 3 files changed, 29 insertions(+), 17 deletions(-) diff --git a/src/browser/Page.zig b/src/browser/Page.zig index 52d41d86..03a93a01 100644 --- a/src/browser/Page.zig +++ b/src/browser/Page.zig @@ -113,8 +113,10 @@ _intersection_delivery_scheduled: bool = false, _slots_pending_slotchange: std.AutoHashMapUnmanaged(*Element.Html.Slot, void) = .{}, _slotchange_delivery_scheduled: bool = false, -// List of active PerformanceObservers. +/// List of active PerformanceObservers. +/// Contrary to MutationObserver and IntersectionObserver, these are regular tasks. _performance_observers: std.ArrayList(*PerformanceObserver) = .{}, +_performance_delivery_scheduled: bool = false, // Lookup for customized built-in elements. Maps element pointer to definition. _customized_builtin_definitions: std.AutoHashMapUnmanaged(*Element, *CustomElementDefinition) = .{}, @@ -951,6 +953,16 @@ fn printWaitAnalysis(self: *Page) void { } } +pub fn tick(self: *Page) void { + if (comptime IS_DEBUG) { + log.debug(.page, "tick", .{}); + } + _ = self.scheduler.run() catch |err| { + log.err(.page, "tick", .{ .err = err }); + }; + self.js.runMicrotasks(); +} + pub fn isGoingAway(self: *const Page) bool { return self._queued_navigation != null; } @@ -1045,8 +1057,7 @@ pub fn unregisterPerformanceObserver(self: *Page, observer: *PerformanceObserver } /// Updates performance observers with the new entry. -/// This doesn't emit callbacks but rather fills the queues of observers; -/// microtask queue runs them periodically. +/// This doesn't emit callbacks but rather fills the queues of observers. pub fn notifyPerformanceObservers(self: *Page, entry: *Performance.Entry) !void { for (self._performance_observers.items) |observer| { if (observer.interested(entry)) { @@ -1055,6 +1066,8 @@ pub fn notifyPerformanceObservers(self: *Page, entry: *Performance.Entry) !void }; } } + + self._performance_delivery_scheduled = true; } pub fn registerMutationObserver(self: *Page, observer: *MutationObserver) !void { diff --git a/src/browser/js/Context.zig b/src/browser/js/Context.zig index a51c3a55..0d2a7040 100644 --- a/src/browser/js/Context.zig +++ b/src/browser/js/Context.zig @@ -2017,16 +2017,6 @@ fn zigJsonToJs(isolate: v8.Isolate, v8_context: v8.Context, value: std.json.Valu } // Microtasks -pub fn queuePerformanceDelivery(self: *Context) !void { - self.isolate.enqueueMicrotask(struct { - fn run(data: ?*anyopaque) callconv(.c) void { - const page: *Page = @ptrCast(@alignCast(data.?)); - _ = page; - @panic("TODO"); - } - }, self.page); -} - pub fn queueMutationDelivery(self: *Context) !void { self.isolate.enqueueMicrotask(struct { fn run(data: ?*anyopaque) callconv(.c) void { diff --git a/src/browser/webapi/PerformanceObserver.zig b/src/browser/webapi/PerformanceObserver.zig index dbaed6d4..be920c1a 100644 --- a/src/browser/webapi/PerformanceObserver.zig +++ b/src/browser/webapi/PerformanceObserver.zig @@ -121,18 +121,27 @@ pub fn takeRecords(self: *PerformanceObserver, page: *Page) ![]*Performance.Entr return records; } +pub fn getSupportedEntryTypes(_: *const PerformanceObserver) []const []const u8 { + return &.{ "mark", "measure" }; +} + /// Returns true if observer interested with given entry. pub fn interested( self: *const PerformanceObserver, entry: *const Performance.Entry, ) bool { - const index = @as(u16, @intFromEnum(entry._type)); - const flag = @as(u16, 1) << index; + const flag = @as(u16, 1) << @intCast(@intFromEnum(entry._type)); return self._interests & flag != 0; } -pub fn getSupportedEntryTypes(_: *const PerformanceObserver) []const []const u8 { - return &.{ "mark", "measure" }; +pub inline fn hasRecords(self: *const PerformanceObserver) bool { + return self._entries.items.len > 0; +} + +/// Runs the PerformanceObserver's callback with records; emptying it out. +pub fn dispatch(self: *PerformanceObserver, page: *Page) !void { + const records = try self.takeRecords(page); + _ = try self._callback.call(void, .{records}); } pub const JsApi = struct {