From 2b95b1e743ea7fc05d3cbc2cfd6da0601b69e487 Mon Sep 17 00:00:00 2001 From: Karl Seguin Date: Fri, 1 May 2026 09:06:47 +0800 Subject: [PATCH] More aggressive popup cleanup, more efficient load tick Follow up to https://github.com/lightpanda-io/browser/pull/2335 which hooks into the tick's GC hint to close any closed window (rather than having to wait until page unload). Also, use schedule task for dispatchLoad which removes an check in every tick. --- src/browser/Frame.zig | 15 ++++++++++++++- src/browser/Page.zig | 12 ++++++++---- src/browser/Runner.zig | 4 +--- src/browser/webapi/element/html/Image.zig | 2 +- src/browser/webapi/element/html/Link.zig | 2 +- src/browser/webapi/element/html/Style.zig | 2 +- 6 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/browser/Frame.zig b/src/browser/Frame.zig index 5edc027f..c26c6a76 100644 --- a/src/browser/Frame.zig +++ b/src/browser/Frame.zig @@ -1596,7 +1596,20 @@ pub fn checkIntersections(self: *Frame) !void { } } -pub fn dispatchLoad(self: *Frame) !void { +pub fn queueLoad(self: *Frame, html: *Element.Html) !void { + try self._to_load.append(self.arena, html); + if (self._to_load.items.len == 1) { + try self.js.scheduler.add(self, struct { + fn cleanup(ctx: *anyopaque) !?u32 { + const f: *Frame = @ptrCast(@alignCast(ctx)); + try f.dispatchLoad(); + return null; + } + }.cleanup, 0, .{ .name = "frame.dispatchLoad" }); + } +} + +fn dispatchLoad(self: *Frame) !void { const has_dom_load_listener = self._event_manager.has_dom_load_listener; // Swap buffers - new additions during dispatch go to the other buffer diff --git a/src/browser/Page.zig b/src/browser/Page.zig index 927d2f05..1848692d 100644 --- a/src/browser/Page.zig +++ b/src/browser/Page.zig @@ -121,10 +121,7 @@ pub fn init(self: *Page, session: *Session, frame_id: u32) !void { // Tear down the Page and its root Frame. Equivalent to the old // Session.removePage + Session.resetFrameResources. pub fn deinit(self: *Page, abort_http: bool) void { - for (self.queued_close.items) |popup| { - popup.deinit(abort_http); - } - self.queued_close = .empty; + self.cleanupClosedPopups(); for (self.popups.items) |popup| { popup.deinit(abort_http); @@ -179,6 +176,13 @@ pub fn deinit(self: *Page, abort_http: bool) void { session.arena_pool.release(self.frame_arena); } +pub fn cleanupClosedPopups(self: *Page) void { + for (self.queued_close.items) |popup| { + popup.deinit(true); + } + self.queued_close = .empty; +} + pub fn getArena(self: *Page, size_or_bucket: anytype, debug: []const u8) !Allocator { return self.session.getArena(size_or_bucket, debug); } diff --git a/src/browser/Runner.zig b/src/browser/Runner.zig index 2489382e..c1f0ce89 100644 --- a/src/browser/Runner.zig +++ b/src/browser/Runner.zig @@ -84,6 +84,7 @@ fn _wait(self: *Runner, comptime is_cdp: bool, opts: WaitOpts) !CDPWaitResult { while (true) { if (gc_hint_timer.read() >= gc_hint_period_ns) { gc_hint_timer.reset(); + self.frame._page.cleanupClosedPopups(); self.session.browser.env.memoryPressureNotification(.moderate); } @@ -181,9 +182,6 @@ fn _tick(self: *Runner, comptime is_cdp: bool, opts: TickOpts) !CDPTickResult { // it AFTER. try browser.runMacrotasks(); - // Each call to this runs scheduled load events. - try frame.dispatchLoad(); - const http_active = http_client.http_active; const total_network_activity = http_active + http_client.interception_layer.intercepted; if (frame._notified_network_almost_idle.check(total_network_activity <= 2)) { diff --git a/src/browser/webapi/element/html/Image.zig b/src/browser/webapi/element/html/Image.zig index ab60c943..dab4f4d5 100644 --- a/src/browser/webapi/element/html/Image.zig +++ b/src/browser/webapi/element/html/Image.zig @@ -128,7 +128,7 @@ pub fn imageAddedCallback(self: *Image, frame: *Frame) !void { const src = element.getAttributeSafe(comptime .wrap("src")) orelse return; if (src.len == 0) return; - try frame._to_load.append(frame.arena, self._proto); + try frame.queueLoad(self._proto); } pub const JsApi = struct { diff --git a/src/browser/webapi/element/html/Link.zig b/src/browser/webapi/element/html/Link.zig index a1a14874..8f561355 100644 --- a/src/browser/webapi/element/html/Link.zig +++ b/src/browser/webapi/element/html/Link.zig @@ -106,7 +106,7 @@ pub fn linkAddedCallback(self: *Link, frame: *Frame) !void { return; } - try frame._to_load.append(frame.arena, self._proto); + try frame.queueLoad(self._proto); } pub const JsApi = struct { diff --git a/src/browser/webapi/element/html/Style.zig b/src/browser/webapi/element/html/Style.zig index 95e0bc0d..a7b21b64 100644 --- a/src/browser/webapi/element/html/Style.zig +++ b/src/browser/webapi/element/html/Style.zig @@ -113,7 +113,7 @@ pub fn styleAddedCallback(self: *Style, frame: *Frame) !void { return; } - try frame._to_load.append(frame.arena, self._proto); + try frame.queueLoad(self._proto); } pub const JsApi = struct {