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.
This commit is contained in:
Halil Durak
2025-12-22 13:19:00 +03:00
parent c80a1601b7
commit 7c1758a90f
3 changed files with 29 additions and 17 deletions

View File

@@ -115,8 +115,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) = .{},
@@ -969,6 +971,16 @@ pub fn tick(self: *Page) void {
_ = self.scheduler.run() catch |err| {
log.err(.page, "tick", .{ .err = err });
};
// Dispatch performance observer events.
for (self._performance_observers.items) |observer| {
if (observer.hasRecords()) {
observer.dispatch(self) catch |err| {
log.err(.page, "tcik", .{ .err = err });
};
}
}
self.js.runMicrotasks();
}
@@ -1066,8 +1078,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)) {
@@ -1076,6 +1087,8 @@ pub fn notifyPerformanceObservers(self: *Page, entry: *Performance.Entry) !void
};
}
}
self._performance_delivery_scheduled = true;
}
pub fn registerMutationObserver(self: *Page, observer: *MutationObserver) !void {

View File

@@ -2009,16 +2009,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 {

View File

@@ -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 {