From ca8877da2d71cd40c18d517d6696a513ddaef43d Mon Sep 17 00:00:00 2001 From: Karl Seguin Date: Fri, 5 Sep 2025 18:17:55 +0800 Subject: [PATCH] Fix blockingGet during blockingGet ScriptManager should only ever has one in-flight blockingGet. The is_blocking flag is used to assert this, as well as enforce it in evaluate(). If is_blocking is true, evaluate() exits. This doesn't work for async scripts however, as they aren't executed via evaluate(), but rather execute directly once complete. This PR changes the execution behavior of async scripts. They are now only executed in evaluate() (and thus won't execute when is_blocking == true). However, unlike normal/deferred scripts, async scripts continue to execute in their completion order (not their declared order). Fixes https://github.com/lightpanda-io/browser/issues/1016 --- src/browser/ScriptManager.zig | 84 +++++++++++++++++++---------------- 1 file changed, 45 insertions(+), 39 deletions(-) diff --git a/src/browser/ScriptManager.zig b/src/browser/ScriptManager.zig index 36d47778..c3af725d 100644 --- a/src/browser/ScriptManager.zig +++ b/src/browser/ScriptManager.zig @@ -35,7 +35,7 @@ const ScriptManager = @This(); page: *Page, -// used to prevent recursive evalution +// used to prevent recursive evalutaion is_evaluating: bool, // used to prevent executing scripts while we're doing a blocking load @@ -45,10 +45,16 @@ is_blocking: bool = false, static_scripts_done: bool, // List of async scripts. We don't care about the execution order of these, but -// on shutdown/abort, we need to co cleanup any pending ones. +// on shutdown/abort, we need to cleanup any pending ones. asyncs: OrderList, -// Normal scripts (non-deffered & non-async). These must be executed ni order +// When an async script is ready to be evaluated, it's moved from asyncs to +// this list. You might think we can evaluate an async script as soon as it's +// done, but we can only evaluate scripts when `is_blocking == false`. So this +// becomes a list of scripts to execute on the next evaluate(). +asyncs_ready: OrderList, + +// Normal scripts (non-deferred & non-async). These must be executed in order scripts: OrderList, // List of deferred scripts. These must be executed in order, but only once @@ -72,6 +78,7 @@ pub fn init(browser: *Browser, page: *Page) ScriptManager { .asyncs = .{}, .scripts = .{}, .deferreds = .{}, + .asyncs_ready = .{}, .is_evaluating = false, .allocator = allocator, .client = browser.http_client, @@ -91,6 +98,7 @@ pub fn reset(self: *ScriptManager) void { self.clearList(&self.asyncs); self.clearList(&self.scripts); self.clearList(&self.deferreds); + self.clearList(&self.asyncs_ready); self.static_scripts_done = false; } @@ -114,7 +122,7 @@ pub fn addFromElement(self: *ScriptManager, element: *parser.Element) !void { // document.getElementsByTagName('head')[0].appendChild(script) // that script tag will immediately get executed by our scriptAddedCallback. // However, if the location where the script tag is inserted happens to be - // below where processHTMLDoc curently is, then we'll re-run that same script + // below where processHTMLDoc currently is, then we'll re-run that same script // again in processHTMLDoc. This flag is used to let us know if a specific //