performance optimization: batch fetch availableDates

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>
This commit is contained in:
google-labs-jules[bot]
2026-03-10 14:00:03 +00:00
parent a28e8be326
commit d365b71ee6
4 changed files with 128 additions and 60 deletions

View File

@@ -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();

View File

@@ -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();

View File

@@ -783,41 +783,51 @@ async function loadMenuDataFromAPI() {
const allDays = []; const allDays = [];
let completed = 0; let completed = 0;
for (const dateObj of availableDates) { const BATCH_SIZE = 5;
const dateStr = dateObj.date; for (let i = 0; i < totalDates; i += BATCH_SIZE) {
const pct = Math.round(((completed + 1) / totalDates) * 100); const batch = availableDates.slice(i, i + BATCH_SIZE);
progressFill.style.width = `${pct}%`; const results = await Promise.all(batch.map(async (dateObj) => {
progressPercent.textContent = `${pct}%`; const dateStr = dateObj.date;
progressMessage.textContent = `Lade Menü für ${dateStr}...`; 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 { if (detailResp.ok) {
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}/`, { const detailData = await detailResp.json();
headers: (0,_api_js__WEBPACK_IMPORTED_MODULE_3__/* .apiHeaders */ .H)(token) const menuGroups = detailData.results || [];
}); let dayItems = [];
for (const group of menuGroups) {
if (detailResp.ok) { if (group.items && Array.isArray(group.items)) {
const detailData = await detailResp.json(); dayItems = dayItems.concat(group.items);
const menuGroups = detailData.results || []; }
let dayItems = []; }
for (const group of menuGroups) { if (dayItems.length > 0) {
if (group.items && Array.isArray(group.items)) { dayData = {
dayItems = dayItems.concat(group.items); date: dateStr,
menu_items: dayItems,
orders: dateObj.orders || []
};
} }
} }
if (dayItems.length > 0) { } catch (err) {
allDays.push({ console.error(`Failed to fetch details for ${dateStr}:`, err);
date: dateStr, } finally {
menu_items: dayItems, completed++;
orders: dateObj.orders || [] const pct = Math.round((completed / totalDates) * 100);
}); progressFill.style.width = `${pct}%`;
} progressPercent.textContent = `${pct}%`;
progressMessage.textContent = `Lade Menü für ${dateStr}...`;
} }
} catch (err) { return dayData;
console.error(`Failed to fetch details for ${dateStr}:`, err); }));
}
completed++; for (const result of results) {
await new Promise(r => setTimeout(r, 100)); if (result) {
allDays.push(result);
}
}
} }
const weeksMap = new Map(); const weeksMap = new Map();

View File

@@ -752,41 +752,51 @@ export async function loadMenuDataFromAPI() {
const allDays = []; const allDays = [];
let completed = 0; let completed = 0;
for (const dateObj of availableDates) { const BATCH_SIZE = 5;
const dateStr = dateObj.date; for (let i = 0; i < totalDates; i += BATCH_SIZE) {
const pct = Math.round(((completed + 1) / totalDates) * 100); const batch = availableDates.slice(i, i + BATCH_SIZE);
progressFill.style.width = `${pct}%`; const results = await Promise.all(batch.map(async (dateObj) => {
progressPercent.textContent = `${pct}%`; const dateStr = dateObj.date;
progressMessage.textContent = `Lade Menü für ${dateStr}...`; let dayData = null;
try {
const detailResp = await fetch(`${API_BASE}/venues/${VENUE_ID}/menu/${MENU_ID}/${dateStr}/`, {
headers: apiHeaders(token)
});
try { if (detailResp.ok) {
const detailResp = await fetch(`${API_BASE}/venues/${VENUE_ID}/menu/${MENU_ID}/${dateStr}/`, { const detailData = await detailResp.json();
headers: apiHeaders(token) const menuGroups = detailData.results || [];
}); let dayItems = [];
for (const group of menuGroups) {
if (detailResp.ok) { if (group.items && Array.isArray(group.items)) {
const detailData = await detailResp.json(); dayItems = dayItems.concat(group.items);
const menuGroups = detailData.results || []; }
let dayItems = []; }
for (const group of menuGroups) { if (dayItems.length > 0) {
if (group.items && Array.isArray(group.items)) { dayData = {
dayItems = dayItems.concat(group.items); date: dateStr,
menu_items: dayItems,
orders: dateObj.orders || []
};
} }
} }
if (dayItems.length > 0) { } catch (err) {
allDays.push({ console.error(`Failed to fetch details for ${dateStr}:`, err);
date: dateStr, } finally {
menu_items: dayItems, completed++;
orders: dateObj.orders || [] const pct = Math.round((completed / totalDates) * 100);
}); progressFill.style.width = `${pct}%`;
} progressPercent.textContent = `${pct}%`;
progressMessage.textContent = `Lade Menü für ${dateStr}...`;
} }
} catch (err) { return dayData;
console.error(`Failed to fetch details for ${dateStr}:`, err); }));
}
completed++; for (const result of results) {
await new Promise(r => setTimeout(r, 100)); if (result) {
allDays.push(result);
}
}
} }
const weeksMap = new Map(); const weeksMap = new Map();