introduce dispatchLoad and move load dispatching to Session._wait

This commit is contained in:
Halil Durak
2026-02-25 16:04:58 +03:00
parent be858ac9ce
commit e23604e08d
2 changed files with 16 additions and 47 deletions

View File

@@ -723,22 +723,13 @@ pub fn documentIsComplete(self: *Page) void {
fn _documentIsComplete(self: *Page) !void {
self.document._ready_state = .complete;
// Run load events before window.load.
try self.dispatchLoad();
var ls: JS.Local.Scope = undefined;
self.js.localScope(&ls);
defer ls.deinit();
{
// Dispatch `_to_load` events before window.load.
const has_dom_load_listener = self._event_manager.has_dom_load_listener;
for (self._to_load.items) |html_element| {
if (has_dom_load_listener or html_element.hasAttributeFunction(.onload, self)) {
const event = try Event.initTrusted(comptime .wrap("load"), .{}, self);
try self._event_manager.dispatch(html_element.asEventTarget(), event);
}
}
}
self._to_load.clearRetainingCapacity();
// Dispatch window.load event.
const event = try Event.initTrusted(comptime .wrap("load"), .{}, self);
// This event is weird, it's dispatched directly on the window, but
@@ -1059,14 +1050,7 @@ pub fn linkAddedCallback(self: *Page, link: *Element.Html.Link) !void {
const href = element.getAttributeSafe(comptime .wrap("href")) orelse return;
if (href.len == 0) return;
// If `_to_load` len was 0, we have to schedule a callback on scheduler.
const loads = &self._to_load;
const not_scheduled = loads.items.len == 0;
try loads.append(self.arena, link._proto);
if (not_scheduled) {
try self.scheduleLoadEventDelivery();
}
try self._to_load.append(self.arena, link._proto);
}
pub fn domChanged(self: *Page) void {
@@ -1241,34 +1225,16 @@ pub fn checkIntersections(self: *Page) !void {
}
}
pub fn scheduleLoadEventDelivery(self: *Page) !void {
// The dispatcher function.
const callback = struct {
fn callback(ptr: *anyopaque) anyerror!?u32 {
const page: *Page = @ptrCast(@alignCast(ptr));
const has_dom_load_listener = page._event_manager.has_dom_load_listener;
for (page._to_load.items) |html_element| {
if (has_dom_load_listener or html_element.hasAttributeFunction(.onload, page)) {
const event = try Event.initTrusted(comptime .wrap("load"), .{}, page);
try page._event_manager.dispatch(html_element.asEventTarget(), event);
}
}
// We drained everything.
page._to_load.clearRetainingCapacity();
return null;
pub fn dispatchLoad(self: *Page) !void {
const has_dom_load_listener = self._event_manager.has_dom_load_listener;
for (self._to_load.items) |html_element| {
if (has_dom_load_listener or html_element.hasAttributeFunction(.onload, self)) {
const event = try Event.initTrusted(comptime .wrap("load"), .{}, self);
try self._event_manager.dispatch(html_element.asEventTarget(), event);
}
}.callback;
return self.js.scheduler.add(
self,
callback,
0,
.{
.low_priority = false,
.name = "scheduleLoadEventDelivery",
},
);
}
// We drained everything.
self._to_load.clearRetainingCapacity();
}
pub fn scheduleMutationDelivery(self: *Page) !void {

View File

@@ -241,6 +241,9 @@ fn _wait(self: *Session, page: *Page, wait_ms: u32) !WaitResult {
// it AFTER.
const ms_to_next_task = try browser.runMacrotasks();
// Each call to this runs scheduled load events.
try page.dispatchLoad();
const http_active = http_client.active;
const total_network_activity = http_active + http_client.intercepted;
if (page._notified_network_almost_idle.check(total_network_activity <= 2)) {