Opening the Favorites tab issues one events.php request per stored favorite, one after another, even though the calling code explicitly asks for cache-only data by passing {fetch: false}. The guard it passes that flag to is inverted, so it gets the opposite of what it asks for.
Reproducing
npm run dev, then open http://localhost:3080/events/
- Open a few rides and favorite each one (the star button on the event details page)
- Reload the page — this matters, see the note below
- Open DevTools → Network and filter for
events.php
- Click through to the Favorites tab
Expected: no requests. The favorites list renders from local storage.
Actual: one events.php?id=N request per favorite, each starting only after the previous one finishes.
With 4 favorites stored I measured 4 requests taking 11 ms, 2.1 ms, 1.9 ms and 1.9 ms, starting at +0, +11.3, +13.5 and +15.5 ms — 17.3 ms of wall time on localhost. The start offsets line up with the preceding request's completion, which confirms they are serialised rather than merely issued in quick succession.
The reload in step 3 matters because dataPool keeps an in-memory caldaily_map. If you favorited the rides in the same page session they are already cached, the early-return hides the bug and you see nothing. A fresh load is the normal case anyway — someone opening the app and tapping Favorites.
Cause
cal/src/support/favorites.js asks for cache-only data:
// if we have retrieved this event recently; update it.
// future: background request to update all ( or a page of ) favorite data.
const [ series_id, single_id ] = key.split('-');
const evt = await dataPool.getDaily(single_id, {fetch: false});
But the guard in cal/src/support/dataPool.js is inverted:
async getDaily(caldaily_id, options = null) {
const cached = caldaily_map.get(caldaily_id);
if (cached) {
return cached;
} else if (!options || options.fetch === false) {
// ...performs the network fetch
The branch runs the fetch when fetch is false. Because that await sits inside a for loop over every stored key, the requests are also serialised.
A second consequence: getDaily(id, {fetch: true}) matches neither branch and returns undefined. Nothing calls it that way today, so it is latent rather than broken.
Suggested fix, and the one thing it changes
- } else if (!options || options.fetch === false) {
+ } else if (!options || options.fetch !== false) {
I tried this locally: the Favorites tab makes 0 requests and all four favorites still render correctly, with the right titles, dates and times, straight from local storage.
To be upfront about the trade-off — these requests are not doing nothing. updateStorage runs the response back through pick(), the same subset filter used when the favorite was created, so the fetch cannot add any field the stored copy lacks. What it can do is refresh values: a ride cancelled or retimed after you favorited it currently gets picked up here. After this change, a favorite would show what it showed when you saved it until you open it.
That looks like the intended design rather than a regression:
pick()'s own comment says "doesn't store newsflash: there's no fast refresh; it might be stale."
- The comment at the call site describes a background refresh as future work.
docs/CalVue.md lists both "a disclaimer about opening each favorite to see the latest information" and "future: server helper to quick update favorite status" as open items.
So the accidental refresh is doing a job nobody has designed yet, in the least efficient shape available — serially, on the critical path, on every visit. If you would rather keep refreshing, the fix is still correct and the refresh wants to become deliberate: batched or parallel rather than one awaited request per favorite.
Impact
Negligible on localhost, but it is a serial chain in front of the render. On a mobile connection at 100–300 ms per round trip, twenty favorites would be several seconds before the view settles. It is also avoidable load on the API box for data the client already has.
Possibly related to the "favorites need pagination" item in docs/CalVue.md — some of what makes that page feel slow may be this rather than the rendering.
Opening the Favorites tab issues one
events.phprequest per stored favorite, one after another, even though the calling code explicitly asks for cache-only data by passing{fetch: false}. The guard it passes that flag to is inverted, so it gets the opposite of what it asks for.Reproducing
npm run dev, then openhttp://localhost:3080/events/events.phpExpected: no requests. The favorites list renders from local storage.
Actual: one
events.php?id=Nrequest per favorite, each starting only after the previous one finishes.With 4 favorites stored I measured 4 requests taking 11 ms, 2.1 ms, 1.9 ms and 1.9 ms, starting at +0, +11.3, +13.5 and +15.5 ms — 17.3 ms of wall time on localhost. The start offsets line up with the preceding request's completion, which confirms they are serialised rather than merely issued in quick succession.
The reload in step 3 matters because
dataPoolkeeps an in-memorycaldaily_map. If you favorited the rides in the same page session they are already cached, the early-return hides the bug and you see nothing. A fresh load is the normal case anyway — someone opening the app and tapping Favorites.Cause
cal/src/support/favorites.jsasks for cache-only data:But the guard in
cal/src/support/dataPool.jsis inverted:The branch runs the fetch when
fetchisfalse. Because thatawaitsits inside aforloop over every stored key, the requests are also serialised.A second consequence:
getDaily(id, {fetch: true})matches neither branch and returnsundefined. Nothing calls it that way today, so it is latent rather than broken.Suggested fix, and the one thing it changes
I tried this locally: the Favorites tab makes 0 requests and all four favorites still render correctly, with the right titles, dates and times, straight from local storage.
To be upfront about the trade-off — these requests are not doing nothing.
updateStorageruns the response back throughpick(), the same subset filter used when the favorite was created, so the fetch cannot add any field the stored copy lacks. What it can do is refresh values: a ride cancelled or retimed after you favorited it currently gets picked up here. After this change, a favorite would show what it showed when you saved it until you open it.That looks like the intended design rather than a regression:
pick()'s own comment says "doesn't store newsflash: there's no fast refresh; it might be stale."docs/CalVue.mdlists both "a disclaimer about opening each favorite to see the latest information" and "future: server helper to quick update favorite status" as open items.So the accidental refresh is doing a job nobody has designed yet, in the least efficient shape available — serially, on the critical path, on every visit. If you would rather keep refreshing, the fix is still correct and the refresh wants to become deliberate: batched or parallel rather than one awaited request per favorite.
Impact
Negligible on localhost, but it is a serial chain in front of the render. On a mobile connection at 100–300 ms per round trip, twenty favorites would be several seconds before the view settles. It is also avoidable load on the API box for data the client already has.
Possibly related to the "favorites need pagination" item in
docs/CalVue.md— some of what makes that page feel slow may be this rather than the rendering.