From d365b71ee61f80ea0b275de582950fd20c81f61a Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Tue, 10 Mar 2026 14:00:03 +0000 Subject: [PATCH] =?UTF-8?q?=E2=9A=A1=20performance=20optimization:=20batch?= =?UTF-8?q?=20fetch=20availableDates?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removed the 100ms artificial delay in `loadMenuDataFromAPI` and switched from sequentially awaiting fetch requests to concurrently awaiting requests in batches of 5 using `Promise.all`. Preserved original chronological ordering of array elements. Co-authored-by: TauNeutrino <1600410+TauNeutrino@users.noreply.github.com> --- benchmark_loadMenuDataFromAPI.js | 22 +++++++ benchmark_loadMenuDataFromAPI_concurrent.js | 26 ++++++++ dist/kantine.bundle.js | 70 ++++++++++++--------- src/actions.js | 70 ++++++++++++--------- 4 files changed, 128 insertions(+), 60 deletions(-) create mode 100644 benchmark_loadMenuDataFromAPI.js create mode 100644 benchmark_loadMenuDataFromAPI_concurrent.js diff --git a/benchmark_loadMenuDataFromAPI.js b/benchmark_loadMenuDataFromAPI.js new file mode 100644 index 0000000..7cc8a99 --- /dev/null +++ b/benchmark_loadMenuDataFromAPI.js @@ -0,0 +1,22 @@ +const fs = require('fs'); + +async function benchmark() { + // We will simulate the same exact loop in src/actions.js + let availableDates = Array.from({length: 30}).map((_, i) => ({ date: `2024-01-${i+1}`})); + const totalDates = availableDates.length; + let completed = 0; + + console.log(`Starting benchmark for ${totalDates} items (Sequential with 100ms artificial delay)`); + const start = Date.now(); + for (const dateObj of availableDates) { + // mock fetch + await new Promise(r => setTimeout(r, 50)); // simulate network delay + + completed++; + await new Promise(r => setTimeout(r, 100)); // the artificial delay in codebase + } + const end = Date.now(); + console.log(`Sequential loading took ${end - start}ms`); +} + +benchmark(); diff --git a/benchmark_loadMenuDataFromAPI_concurrent.js b/benchmark_loadMenuDataFromAPI_concurrent.js new file mode 100644 index 0000000..f63f2fd --- /dev/null +++ b/benchmark_loadMenuDataFromAPI_concurrent.js @@ -0,0 +1,26 @@ +const fs = require('fs'); + +async function benchmark() { + let availableDates = Array.from({length: 30}).map((_, i) => ({ date: `2024-01-${i+1}`})); + const totalDates = availableDates.length; + let completed = 0; + + console.log(`Starting benchmark for ${totalDates} items (Concurrent batch=5 without 100ms artificial delay)`); + const start = Date.now(); + + // Simulate Promise.all batching approach + const BATCH_SIZE = 5; + for (let i = 0; i < totalDates; i += BATCH_SIZE) { + const batch = availableDates.slice(i, i + BATCH_SIZE); + await Promise.all(batch.map(async (dateObj) => { + // mock fetch + await new Promise(r => setTimeout(r, 50)); // simulate network delay + completed++; + })); + } + + const end = Date.now(); + console.log(`Concurrent loading took ${end - start}ms`); +} + +benchmark(); diff --git a/dist/kantine.bundle.js b/dist/kantine.bundle.js index 8b8c0b3..5d2457b 100644 --- a/dist/kantine.bundle.js +++ b/dist/kantine.bundle.js @@ -783,41 +783,51 @@ async function loadMenuDataFromAPI() { const allDays = []; let completed = 0; - for (const dateObj of availableDates) { - const dateStr = dateObj.date; - const pct = Math.round(((completed + 1) / totalDates) * 100); - progressFill.style.width = `${pct}%`; - progressPercent.textContent = `${pct}%`; - progressMessage.textContent = `Lade Menü für ${dateStr}...`; + const BATCH_SIZE = 5; + for (let i = 0; i < totalDates; i += BATCH_SIZE) { + const batch = availableDates.slice(i, i + BATCH_SIZE); + const results = await Promise.all(batch.map(async (dateObj) => { + const dateStr = dateObj.date; + let dayData = null; + try { + const detailResp = await fetch(`${_constants_js__WEBPACK_IMPORTED_MODULE_2__/* .API_BASE */ .tE}/venues/${_constants_js__WEBPACK_IMPORTED_MODULE_2__/* .VENUE_ID */ .eW}/menu/${_constants_js__WEBPACK_IMPORTED_MODULE_2__/* .MENU_ID */ .YU}/${dateStr}/`, { + headers: (0,_api_js__WEBPACK_IMPORTED_MODULE_3__/* .apiHeaders */ .H)(token) + }); - try { - const detailResp = await fetch(`${_constants_js__WEBPACK_IMPORTED_MODULE_2__/* .API_BASE */ .tE}/venues/${_constants_js__WEBPACK_IMPORTED_MODULE_2__/* .VENUE_ID */ .eW}/menu/${_constants_js__WEBPACK_IMPORTED_MODULE_2__/* .MENU_ID */ .YU}/${dateStr}/`, { - headers: (0,_api_js__WEBPACK_IMPORTED_MODULE_3__/* .apiHeaders */ .H)(token) - }); - - if (detailResp.ok) { - const detailData = await detailResp.json(); - const menuGroups = detailData.results || []; - let dayItems = []; - for (const group of menuGroups) { - if (group.items && Array.isArray(group.items)) { - dayItems = dayItems.concat(group.items); + if (detailResp.ok) { + const detailData = await detailResp.json(); + const menuGroups = detailData.results || []; + let dayItems = []; + for (const group of menuGroups) { + if (group.items && Array.isArray(group.items)) { + dayItems = dayItems.concat(group.items); + } + } + if (dayItems.length > 0) { + dayData = { + date: dateStr, + menu_items: dayItems, + orders: dateObj.orders || [] + }; } } - if (dayItems.length > 0) { - allDays.push({ - date: dateStr, - menu_items: dayItems, - orders: dateObj.orders || [] - }); - } + } catch (err) { + console.error(`Failed to fetch details for ${dateStr}:`, err); + } finally { + completed++; + const pct = Math.round((completed / totalDates) * 100); + progressFill.style.width = `${pct}%`; + progressPercent.textContent = `${pct}%`; + progressMessage.textContent = `Lade Menü für ${dateStr}...`; } - } catch (err) { - console.error(`Failed to fetch details for ${dateStr}:`, err); - } + return dayData; + })); - completed++; - await new Promise(r => setTimeout(r, 100)); + for (const result of results) { + if (result) { + allDays.push(result); + } + } } const weeksMap = new Map(); diff --git a/src/actions.js b/src/actions.js index 54d2ff6..9390d1f 100644 --- a/src/actions.js +++ b/src/actions.js @@ -752,41 +752,51 @@ export async function loadMenuDataFromAPI() { const allDays = []; let completed = 0; - for (const dateObj of availableDates) { - const dateStr = dateObj.date; - const pct = Math.round(((completed + 1) / totalDates) * 100); - progressFill.style.width = `${pct}%`; - progressPercent.textContent = `${pct}%`; - progressMessage.textContent = `Lade Menü für ${dateStr}...`; + const BATCH_SIZE = 5; + for (let i = 0; i < totalDates; i += BATCH_SIZE) { + const batch = availableDates.slice(i, i + BATCH_SIZE); + const results = await Promise.all(batch.map(async (dateObj) => { + const dateStr = dateObj.date; + let dayData = null; + try { + const detailResp = await fetch(`${API_BASE}/venues/${VENUE_ID}/menu/${MENU_ID}/${dateStr}/`, { + headers: apiHeaders(token) + }); - try { - const detailResp = await fetch(`${API_BASE}/venues/${VENUE_ID}/menu/${MENU_ID}/${dateStr}/`, { - headers: apiHeaders(token) - }); - - if (detailResp.ok) { - const detailData = await detailResp.json(); - const menuGroups = detailData.results || []; - let dayItems = []; - for (const group of menuGroups) { - if (group.items && Array.isArray(group.items)) { - dayItems = dayItems.concat(group.items); + if (detailResp.ok) { + const detailData = await detailResp.json(); + const menuGroups = detailData.results || []; + let dayItems = []; + for (const group of menuGroups) { + if (group.items && Array.isArray(group.items)) { + dayItems = dayItems.concat(group.items); + } + } + if (dayItems.length > 0) { + dayData = { + date: dateStr, + menu_items: dayItems, + orders: dateObj.orders || [] + }; } } - if (dayItems.length > 0) { - allDays.push({ - date: dateStr, - menu_items: dayItems, - orders: dateObj.orders || [] - }); - } + } catch (err) { + console.error(`Failed to fetch details for ${dateStr}:`, err); + } finally { + completed++; + const pct = Math.round((completed / totalDates) * 100); + progressFill.style.width = `${pct}%`; + progressPercent.textContent = `${pct}%`; + progressMessage.textContent = `Lade Menü für ${dateStr}...`; } - } catch (err) { - console.error(`Failed to fetch details for ${dateStr}:`, err); - } + return dayData; + })); - completed++; - await new Promise(r => setTimeout(r, 100)); + for (const result of results) { + if (result) { + allDays.push(result); + } + } } const weeksMap = new Map();