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 0264c94426
commit acebbb9041
3 changed files with 29 additions and 17 deletions

View File

@@ -113,8 +113,10 @@ _intersection_delivery_scheduled: bool = false,
_slots_pending_slotchange: std.AutoHashMapUnmanaged(*Element.Html.Slot, void) = .{}, _slots_pending_slotchange: std.AutoHashMapUnmanaged(*Element.Html.Slot, void) = .{},
_slotchange_delivery_scheduled: bool = false, _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_observers: std.ArrayList(*PerformanceObserver) = .{},
_performance_delivery_scheduled: bool = false,
// Lookup for customized built-in elements. Maps element pointer to definition. // Lookup for customized built-in elements. Maps element pointer to definition.
_customized_builtin_definitions: std.AutoHashMapUnmanaged(*Element, *CustomElementDefinition) = .{}, _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 { pub fn isGoingAway(self: *const Page) bool {
return self._queued_navigation != null; return self._queued_navigation != null;
} }
@@ -1045,8 +1057,7 @@ pub fn unregisterPerformanceObserver(self: *Page, observer: *PerformanceObserver
} }
/// Updates performance observers with the new entry. /// Updates performance observers with the new entry.
/// This doesn't emit callbacks but rather fills the queues of observers; /// This doesn't emit callbacks but rather fills the queues of observers.
/// microtask queue runs them periodically.
pub fn notifyPerformanceObservers(self: *Page, entry: *Performance.Entry) !void { pub fn notifyPerformanceObservers(self: *Page, entry: *Performance.Entry) !void {
for (self._performance_observers.items) |observer| { for (self._performance_observers.items) |observer| {
if (observer.interested(entry)) { 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 { pub fn registerMutationObserver(self: *Page, observer: *MutationObserver) !void {

View File

@@ -2017,16 +2017,6 @@ fn zigJsonToJs(isolate: v8.Isolate, v8_context: v8.Context, value: std.json.Valu
} }
// Microtasks // 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 { pub fn queueMutationDelivery(self: *Context) !void {
self.isolate.enqueueMicrotask(struct { self.isolate.enqueueMicrotask(struct {
fn run(data: ?*anyopaque) callconv(.c) void { fn run(data: ?*anyopaque) callconv(.c) void {

View File

@@ -121,18 +121,27 @@ pub fn takeRecords(self: *PerformanceObserver, page: *Page) ![]*Performance.Entr
return records; return records;
} }
pub fn getSupportedEntryTypes(_: *const PerformanceObserver) []const []const u8 {
return &.{ "mark", "measure" };
}
/// Returns true if observer interested with given entry. /// Returns true if observer interested with given entry.
pub fn interested( pub fn interested(
self: *const PerformanceObserver, self: *const PerformanceObserver,
entry: *const Performance.Entry, entry: *const Performance.Entry,
) bool { ) bool {
const index = @as(u16, @intFromEnum(entry._type)); const flag = @as(u16, 1) << @intCast(@intFromEnum(entry._type));
const flag = @as(u16, 1) << index;
return self._interests & flag != 0; return self._interests & flag != 0;
} }
pub fn getSupportedEntryTypes(_: *const PerformanceObserver) []const []const u8 { pub inline fn hasRecords(self: *const PerformanceObserver) bool {
return &.{ "mark", "measure" }; 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 { pub const JsApi = struct {