perf: opstart-fetches /auth/me en /me/data parallel i.p.v. serieel (v0.4.31-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 37s

- Beide verzoeken hangen alleen af van dezelfde sessie-cookie, niet van
  elkaars antwoord - ze werden tot nu toe na elkaar aangeroepen
  (hydrateFromServer() startte pas na een voltooide /auth/me), wat een
  hele round-trip extra kost bij elke opstart voor staf/thuisgebruikers.
- app.js vraagt ze nu tegelijk op via Promise.allSettled; hydrateFromServer()
  krijgt het /me/data-resultaat optioneel meegegeven i.p.v. het zelf
  (opnieuw) op te halen. Voor een leerling/ouder wordt dat resultaat
  genegeerd (zij krijgen sowieso geen whiteboard-data) - nooit verspild
  werk, soms ongebruikt, wat de server niet meer kost dan de bestaande
  losse aanroep die er toch al was.
- De twee andere hydrateFromServer()-aanroepen (na inloggen, na een
  save-conflict) geven bewust niets mee en halen gewoon vers op, zoals
  voorheen - alleen de allereerste opstart kan dit parallelliseren.
- Geverifieerd met de volledige testsuite (112/112) en drie losse
  boot-scenario's in de sandbox (gast/staf/leerling): in alle drie komen
  /auth/me en /me/data binnen ~1ms van elkaar aan (voorheen serieel), en
  blijft het bestaande gedrag (gast blijft gast, staf krijgt het bord,
  leerling krijgt de afgeschermde weergave) exact hetzelfde.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014EPxzBVRXZZnBPvSAaPAbJ
This commit is contained in:
Ramon 2026-07-19 13:43:32 +02:00
parent 4e4aeb4b6d
commit c183c8f931
3 changed files with 20 additions and 7 deletions

View file

@ -1 +1 @@
0.4.30-beta 0.4.31-beta

View file

@ -85,10 +85,17 @@ updateEmptyHint();
(async function(){ (async function(){
updateBoardsUI(); updateBoardsUI();
try{ try{
const me = await api("/auth/me"); /* /auth/me en /me/data hangen allebei alleen af van dezelfde sessie-cookie,
currentUser = me.user; niet van elkaars antwoord - serieel wachten (eerst wie-ben-ik, dan pas
mijn-data ophalen) kost een hele round-trip voor niets. Parallel
opvragen en het tweede antwoord meegeven aan hydrateFromServer()
(die het gewoon negeert voor een leerling/ouder, zie daar) scheelt die
round-trip in het veelvoorkomende geval (staf/thuisgebruiker). */
const [meResult, dataResult] = await Promise.allSettled([api("/auth/me"), api("/me/data")]);
if(meResult.status !== "fulfilled") throw meResult.reason;
currentUser = meResult.value.user;
updateUserUI(); updateUserUI();
await hydrateFromServer(); await hydrateFromServer(dataResult.status === "fulfilled" ? dataResult.value : null);
}catch(e){ }catch(e){
resetToGuest(); resetToGuest();
} }

View file

@ -2,7 +2,7 @@
"use strict"; "use strict";
/* version shown until /api/version resolves (or if the fetch fails, e.g. offline). /* version shown until /api/version resolves (or if the fetch fails, e.g. offline).
Kept in sync by hand with the VERSION file at the repo root on every release. */ Kept in sync by hand with the VERSION file at the repo root on every release. */
const VERSION = "0.4.30-beta"; const VERSION = "0.4.31-beta";
(function(){ (function(){
const tag = document.getElementById("verTag"); const tag = document.getElementById("verTag");
tag.textContent = "v"+VERSION; tag.textContent = "v"+VERSION;
@ -887,7 +887,13 @@ function persistWords(){
function generalExtraFromData(data){ function generalExtraFromData(data){
return (data && data.generalExtra) ? data.generalExtra : {nl:[], en:[]}; return (data && data.generalExtra) ? data.generalExtra : {nl:[], en:[]};
} }
async function hydrateFromServer(){ /* prefetchedData: alleen gebruikt door de opstart-boot in app.js, die /me/data
al parallel met /auth/me heeft opgehaald (zie daar) i.p.v. serieel te
wachten - een leerling/ouder gebruikt het resultaat toch niet (zie de twee
vroege returns hieronder), dus dat verzoek is nooit verspild werk, alleen
soms ongebruikt. Elke andere aanroep (na inloggen, na een save-conflict)
geeft niets mee en haalt gewoon vers op, zoals voorheen. */
async function hydrateFromServer(prefetchedData){
/* schoolleerlingen hebben geen eigen borden - zij zien enkel wat de /* schoolleerlingen hebben geen eigen borden - zij zien enkel wat de
leerkracht heeft toegewezen (zie pupil.js), nooit het whiteboard. leerkracht heeft toegewezen (zie pupil.js), nooit het whiteboard.
Thuiskinderen (leerling zonder school, ouderportaal) vallen hier expres Thuiskinderen (leerling zonder school, ouderportaal) vallen hier expres
@ -911,7 +917,7 @@ async function hydrateFromServer(){
} }
stopPupilView(); stopPupilView();
stopParentView(); stopParentView();
const res = await api("/me/data"); const res = prefetchedData || await api("/me/data");
const d = res.data || {}; const d = res.data || {};
DATA_REV = typeof res.rev === "number" ? res.rev : 0; DATA_REV = typeof res.rev === "number" ? res.rev : 0;
THEMES = themesFromData(d); THEMES = themesFromData(d);