From 8526770e9f0a3dcfe7d08077b21e6a786b964e80 Mon Sep 17 00:00:00 2001 From: Karl Seguin Date: Sat, 21 Mar 2026 11:38:16 +0800 Subject: [PATCH] More aggressive timer cleanup When a timer is cleared, e.g. clearInterval, we flag the task are deleted and maintain the entry in window._timers. When run, the task is ignored and deleted from _timers. This can result in prematurely rejecting timers due to `TooManyTimeout`. One pattern I've seen is a RAF associated with an element where the RAF is cleared (cancelAnimationFrame) if already registered. This can quickly result in TooManyTimers. This commit removes the timer from _timers as soon as it's canceled. It doesn't fully eliminate the chance of TooManyTimeout, but it does reduce it. --- src/browser/webapi/Window.zig | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/browser/webapi/Window.zig b/src/browser/webapi/Window.zig index bbed1010..b89e7383 100644 --- a/src/browser/webapi/Window.zig +++ b/src/browser/webapi/Window.zig @@ -285,23 +285,23 @@ pub fn queueMicrotask(_: *Window, cb: js.Function, page: *Page) void { } pub fn clearTimeout(self: *Window, id: u32) void { - var sc = self._timers.get(id) orelse return; - sc.removed = true; + var sc = self._timers.fetchRemove(id) orelse return; + sc.value.removed = true; } pub fn clearInterval(self: *Window, id: u32) void { - var sc = self._timers.get(id) orelse return; - sc.removed = true; + var sc = self._timers.fetchRemove(id) orelse return; + sc.value.removed = true; } pub fn clearImmediate(self: *Window, id: u32) void { - var sc = self._timers.get(id) orelse return; - sc.removed = true; + var sc = self._timers.fetchRemove(id) orelse return; + sc.value.removed = true; } pub fn cancelAnimationFrame(self: *Window, id: u32) void { - var sc = self._timers.get(id) orelse return; - sc.removed = true; + var sc = self._timers.fetchRemove(id) orelse return; + sc.value.removed = true; } const RequestIdleCallbackOpts = struct { @@ -319,8 +319,8 @@ pub fn requestIdleCallback(self: *Window, cb: js.Function.Temp, opts_: ?RequestI } pub fn cancelIdleCallback(self: *Window, id: u32) void { - var sc = self._timers.get(id) orelse return; - sc.removed = true; + var sc = self._timers.fetchRemove(id) orelse return; + sc.value.removed = true; } pub fn reportError(self: *Window, err: js.Value, page: *Page) !void { @@ -704,7 +704,6 @@ const ScheduleCallback = struct { const window = page.window; if (self.removed) { - _ = window._timers.remove(self.timer_id); self.deinit(); return null; }