From a26e586466ff1907dd78dcdd172cec33865f8300 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Mon, 29 Jun 2026 07:31:38 +0000 Subject: [PATCH] =?UTF-8?q?=E2=9A=A1=20Bolt:=20[performance=20improvement]?= =?UTF-8?q?=20Prevent=20GC=20allocation=20and=20unnecessary=20DOM=20reflow?= =?UTF-8?q?s=20in=20scroll=20event?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 💡 What: Replaced `.forEach()` with a `for` loop and added dirty checking for `.classList` updates in the scroll event listener's requestAnimationFrame. 🎯 Why: `.forEach()` creates a new closure every frame, causing GC thrashing. Unconditional `.classList.remove()` and `.add()` can trigger unnecessary DOM mutation events even if the class is already set/removed. 📊 Impact: Eliminates GC allocation per frame and reduces redundant DOM operations. 🔬 Measurement: Use Performance profiling tool in browser to monitor Garbage Collection pressure and DOM mutations while scrolling. Co-authored-by: kaitoartz <56949089+kaitoartz@users.noreply.github.com> --- .jules/bolt.md | 4 ++++ src/scripts/script.js | 18 ++++++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/.jules/bolt.md b/.jules/bolt.md index 7c27650..93963f5 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -69,3 +69,7 @@ ## 2026-06-02 - Redundant hardware detection calls **Learning:** Calling `performanceManager.detectHardware()` repeatedly to check `isMobile` forces unnecessary recalculations of performance scores, CPU core counts, device memory, and connection types, wasting CPU cycles during initialization and UI interactions. **Action:** Always use the cached `performanceManager.hardware` object (e.g., `performanceManager.hardware.isMobile`) instead of invoking `detectHardware()` directly when checking system capabilities outside of the initial setup. + +## 2025-05-30 - Avoid forEach inside requestAnimationFrame +**Learning:** Using Array iteration methods like `.forEach()` inside a `requestAnimationFrame` loop creates a new closure (function object) every single frame, leading to high garbage collection (GC) pressure and micro-stutters. +**Action:** Replace `.forEach()`, `.map()`, and similar methods with standard `for` loops inside `requestAnimationFrame` loops or high-frequency event handlers. Also add dirty checks before modifying `classList` inside these loops to avoid unnecessary DOM mutation work. diff --git a/src/scripts/script.js b/src/scripts/script.js index e0d5b84..5c844d5 100644 --- a/src/scripts/script.js +++ b/src/scripts/script.js @@ -3808,8 +3808,22 @@ document.addEventListener('DOMContentLoaded', () => { } } - navBtns.forEach(b => b.classList.remove('nav-active')); - activeBtn.classList.add('nav-active'); + /** + * ⚡ Bolt Performance Optimization + * 💡 What: Replaced `.forEach()` with a `for` loop and added dirty checking for `.classList` updates. + * 🎯 Why: `.forEach()` creates a new closure every frame, causing GC thrashing. Unconditional `.classList.remove()` and `.add()` can trigger unnecessary DOM mutation events even if the class is already set/removed. + * 📊 Impact: Eliminates GC allocation per frame and reduces redundant DOM operations. + */ + for (let i = 0; i < navBtns.length; i++) { + const btn = navBtns[i]; + if (btn.classList.contains('nav-active')) { + btn.classList.remove('nav-active'); + } + } + if (!activeBtn.classList.contains('nav-active')) { + activeBtn.classList.add('nav-active'); + } + ticking = false; }); }, { passive: true });