From 1698f43cc9e651c770ffc0f2e0a2e0f53527308b Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Mon, 13 Apr 2026 13:49:02 +0000 Subject: [PATCH] perf(search): precalculate index values for rendering This change improves high-frequency rendering performance in `renderPDFs` by pre-calculating string concatenations, lowercasing, and date formatting values (`_searchStr`, `_isNew`, `_formattedDate`) into memory right after data loading. This offloads the work from the render loop. Co-authored-by: MrAlokTech <107493955+MrAlokTech@users.noreply.github.com> --- .jules/bolt.md | 4 ++++ script.js | 42 ++++++++++++++++++++++++++++++++++-------- 2 files changed, 38 insertions(+), 8 deletions(-) create mode 100644 .jules/bolt.md diff --git a/.jules/bolt.md b/.jules/bolt.md new file mode 100644 index 0000000..9c15082 --- /dev/null +++ b/.jules/bolt.md @@ -0,0 +1,4 @@ + +## 2024-04-13 - [Pre-calculating derived search strings and date formatting] +**Learning:** High-frequency loop performance in lists like `renderPDFs` can degrade severely when performing string concatenations (`pdf.title + pdf.description + ...`), `toLowerCase()` conversions, or `Intl.DateTimeFormat` evaluations dynamically for every item during every render. +**Action:** Always pre-calculate these derived properties (e.g., `_searchStr`, `_formattedDate`, `_isNew`) iteratively immediately after the data completes loading, keeping the render loop extremely lightweight and purely responsible for DOM updates. diff --git a/script.js b/script.js index 22f399d..b3611be 100644 --- a/script.js +++ b/script.js @@ -416,6 +416,34 @@ async function syncClassSwitcher() { renderSemesterTabs(); } +function prepareSearchIndex(data) { + const now = Date.now(); + const sevenDays = 7 * 24 * 60 * 60 * 1000; + const dateFormatter = new Intl.DateTimeFormat('en-US', { + year: 'numeric', month: 'short', day: 'numeric' + }); + + data.forEach(pdf => { + // Pre-calculate search string + const title = pdf.title || ''; + const desc = pdf.description || ''; + const cat = pdf.category || ''; + const author = pdf.author || ''; + pdf._searchStr = `${title} ${desc} ${cat} ${author}`.toLowerCase(); + + // Pre-calculate date properties + const uploadDateObj = new Date(pdf.uploadDate); + if (!isNaN(uploadDateObj.getTime())) { + const timeDiff = now - uploadDateObj.getTime(); + pdf._isNew = timeDiff < sevenDays; + pdf._formattedDate = dateFormatter.format(uploadDateObj); + } else { + pdf._isNew = false; + pdf._formattedDate = "Unknown Date"; + } + }); +} + async function loadPDFDatabase() { if (isMaintenanceActive) return; @@ -454,6 +482,7 @@ async function loadPDFDatabase() { if (shouldUseCache) { pdfDatabase = cachedData; + prepareSearchIndex(pdfDatabase); // --- FIX: CALL THIS TO POPULATE UI --- syncClassSwitcher(); renderSemesterTabs(); @@ -477,6 +506,8 @@ async function loadPDFDatabase() { data: pdfDatabase })); + prepareSearchIndex(pdfDatabase); + // --- FIX: CALL THIS TO POPULATE UI --- syncClassSwitcher(); renderPDFs(); @@ -918,10 +949,7 @@ function renderPDFs() { matchesCategory = currentCategory === 'all' || pdf.category === currentCategory; } - const matchesSearch = pdf.title.toLowerCase().includes(searchTerm) || - pdf.description.toLowerCase().includes(searchTerm) || - pdf.category.toLowerCase().includes(searchTerm) || - pdf.author.toLowerCase().includes(searchTerm); + const matchesSearch = pdf._searchStr ? pdf._searchStr.includes(searchTerm) : false; // Update return statement to include matchesClass return matchesSemester && matchesClass && matchesCategory && matchesSearch; @@ -994,9 +1022,7 @@ function createPDFCard(pdf, favoritesList, index = 0, highlightRegex = null) { const heartIconClass = isFav ? 'fas' : 'far'; const btnActiveClass = isFav ? 'active' : ''; - const uploadDateObj = new Date(pdf.uploadDate); - const timeDiff = new Date() - uploadDateObj; - const isNew = timeDiff < (7 * 24 * 60 * 60 * 1000); // 7 days + const isNew = pdf._isNew || false; const newBadgeHTML = isNew ? `NEW` @@ -1011,7 +1037,7 @@ function createPDFCard(pdf, favoritesList, index = 0, highlightRegex = null) { const categoryIcon = categoryIcons[pdf.category] || 'fa-file-pdf'; // Formatting Date - const formattedDate = new Date(pdf.uploadDate).toLocaleDateString('en-US', { + const formattedDate = pdf._formattedDate || new Date(pdf.uploadDate).toLocaleDateString('en-US', { year: 'numeric', month: 'short', day: 'numeric' });