[PR #1947] [MERGED] perf(book): stop unbounded full-document rescans in quiz numbering fix #34671

Closed
opened 2026-07-14 19:28:28 -05:00 by GiteaMirror · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/harvard-edge/cs249r_book/pull/1947
Author: @farhan523
Created: 7/7/2026
Status: Merged
Merged: 7/10/2026
Merged by: @profvjreddi

Base: devHead: fix/sidebar-quiz-numbering-perf


📝 Commits (1)

  • 854c602 perf(book): stop unbounded full-document rescans in quiz numbering fix

📊 Changes

1 file changed (+10 additions, -5 deletions)

View changed files

📝 book/quarto/assets/scripts/sidebar-auto-collapse.js (+10 -5)

📄 Description

Problem

book/quarto/assets/scripts/sidebar-auto-collapse.js (loaded on every book page) sets up:

const observer = new MutationObserver(() => {
  setTimeout(fixQuizNumbering, 100);
});
observer.observe(document.body, { childList: true, subtree: true });

Every DOM mutation anywhere on the page schedules a fresh, un-debounced fixQuizNumbering() pass, and each pass runs a full-document querySelectorAll over all quiz callouts plus a console.log per renamed element. Consequences on long chapter pages:

  • Mutation bursts (Bootstrap collapses, tooltips, KaTeX typesetting, SocratiQ chat streaming, lightbox) queue dozens of overlapping full-page scans — one timer per mutation — competing with rendering on the main thread for the life of the page.
  • fixQuizNumbering() itself writes textContent, re-triggering the very observer it runs under.
  • The observer never becomes cheap: every pass re-walks and re-regexes every callout, forever.
  • Per-element console.log spam here and in setNavbarActiveState() on every pass.

Users feel this as slower time-to-interactive, scroll/typing jank while SocratiQ streams, and battery drain on long reading sessions.

Fix

  • Mark processed callouts with data-quiz-number-fixed and exclude them via :not([data-quiz-number-fixed]) in the selector — repeat passes match nothing and return immediately. Callouts whose title element isn't rendered yet stay unmarked, so the existing staggered retries (100/500/1000/2000 ms) still pick them up.
  • Debounce the observer with a single re-armed timer, coalescing each mutation burst into one pass instead of one pass per mutation. (The observer only watches childList, so setting the marker attribute cannot re-trigger it.)
  • Remove console.log from the fixQuizNumbering() and setNavbarActiveState() hot paths.

Behavior

No visible change: quiz titles are still renamed ("Self-Check: Question 1.3" → "Self-Check: Question 3"), same retry schedule, and dynamically injected callouts are still processed (new nodes lack the marker attribute). Only the redundant re-scanning is eliminated.

Verified with node --check; diff is +10/−5 lines in one file.


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/harvard-edge/cs249r_book/pull/1947 **Author:** [@farhan523](https://github.com/farhan523) **Created:** 7/7/2026 **Status:** ✅ Merged **Merged:** 7/10/2026 **Merged by:** [@profvjreddi](https://github.com/profvjreddi) **Base:** `dev` ← **Head:** `fix/sidebar-quiz-numbering-perf` --- ### 📝 Commits (1) - [`854c602`](https://github.com/harvard-edge/cs249r_book/commit/854c60242db68b96eab8bd542fcfcb8aa6598be7) perf(book): stop unbounded full-document rescans in quiz numbering fix ### 📊 Changes **1 file changed** (+10 additions, -5 deletions) <details> <summary>View changed files</summary> 📝 `book/quarto/assets/scripts/sidebar-auto-collapse.js` (+10 -5) </details> ### 📄 Description ## Problem `book/quarto/assets/scripts/sidebar-auto-collapse.js` (loaded on every book page) sets up: ```js const observer = new MutationObserver(() => { setTimeout(fixQuizNumbering, 100); }); observer.observe(document.body, { childList: true, subtree: true }); ``` Every DOM mutation anywhere on the page schedules a **fresh, un-debounced** `fixQuizNumbering()` pass, and each pass runs a full-document `querySelectorAll` over all quiz callouts plus a `console.log` per renamed element. Consequences on long chapter pages: - Mutation bursts (Bootstrap collapses, tooltips, KaTeX typesetting, SocratiQ chat streaming, lightbox) queue **dozens of overlapping full-page scans** — one timer per mutation — competing with rendering on the main thread for the life of the page. - `fixQuizNumbering()` itself writes `textContent`, re-triggering the very observer it runs under. - The observer never becomes cheap: every pass re-walks and re-regexes every callout, forever. - Per-element `console.log` spam here and in `setNavbarActiveState()` on every pass. Users feel this as slower time-to-interactive, scroll/typing jank while SocratiQ streams, and battery drain on long reading sessions. ## Fix - **Mark processed callouts** with `data-quiz-number-fixed` and exclude them via `:not([data-quiz-number-fixed])` in the selector — repeat passes match nothing and return immediately. Callouts whose title element isn't rendered yet stay unmarked, so the existing staggered retries (100/500/1000/2000 ms) still pick them up. - **Debounce the observer** with a single re-armed timer, coalescing each mutation burst into one pass instead of one pass per mutation. (The observer only watches `childList`, so setting the marker attribute cannot re-trigger it.) - **Remove `console.log`** from the `fixQuizNumbering()` and `setNavbarActiveState()` hot paths. ## Behavior No visible change: quiz titles are still renamed ("Self-Check: Question 1.3" → "Self-Check: Question 3"), same retry schedule, and dynamically injected callouts are still processed (new nodes lack the marker attribute). Only the redundant re-scanning is eliminated. Verified with `node --check`; diff is +10/−5 lines in one file. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
GiteaMirror added the pull-request label 2026-07-14 19:28:28 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/cs249r_book#34671