The catalog can fetch books while you read the list. api.js keeps one promise per book, so a tap during a prefetch joins the request in flight:
const cache = new Map(); // one promise per book, shared by the prefetch and the route
export function getBook(id) {
const key = Number(id);
if (!cache.has(key)) {
cache.set(key, fetchBook(key).catch((err) => {
cache.delete(key); // let a later tap retry
throw err;
}));
}
return cache.get(key);
}
export const prefetchBooks = (ids) => Promise.all(ids.map(getBook));home.f7 calls prefetchBooks() with every id in pageAfterIn, after its own slide. The route calls getBook(), logs its wait, and delays the preloader by 150 ms with setTimeout, cleared in finally, so a cached book never flashes a spinner. Loading the app, then tapping Gardens in Glass:
2509 ms home pageAfterIn current -> current ... 3120 ms api GET /books/6 -> 200 in 610 ms --- tap Gardens in Glass 126 ms book 6 resolved in 0 ms ... 142 ms book pageBeforeIn next -> current
The slide began at 142 ms instead of about 700. On a real network, prefetch only likely rows, and skip it when navigator.connection.saveData is set.