Bfcache for Client side navigations (SPAs)

679 views
Skip to first unread message

Aditya Punjani

unread,
May 21, 2021, 4:23:14 AM5/21/21
to bfcac...@chromium.org, kenji...@google.com
Hey folks, 

This is just a thought experiment but I was wondering what it would take to make some version of bfcache work for client side apps. Today bfcache works great for document navigations but is not useful in SPA client side navigations.

One of the most common use cases on the web is navigating back and forth between a search results page and various item pages from the search results. 

If we had an API like bfcache.pushState() and bfcache.popState() that could serialize the dom state of the search results page, then we client side navigate to an item page and on back instead of doing a client side navigation we just restore the serialized page from the bfcache. 

This would significantly improve performance in client side apps where client side navigations still require a lot of javascript processing.

Curious if anything along these lines would be feasible? 

Thanks,
Aditya

Kenji Baheux

unread,
Jun 1, 2021, 3:20:40 AM6/1/21
to Aditya Punjani, bfcac...@chromium.org
Hi Aditya,

Sorry for the delay!

I think we had been assuming that Back navigations in SPA, although tedious, didn't leave much room for performance opportunities.
But that was more of a hunch than backed by data. And, recently, I heard similar feedback from other SPA partners who didn't think that the performance of their back navigations was great/on-par with a native BFCache.

You mentioned that client side navigations still require a lot of javascript processing: could you share some numbers or annotated devtools traces ? (feel free to PM me if preferable)

In parallel to performance aspects, it also seems that an API would help the UA understand what's going on, and allow it to manage memory usage (e.g. evict the oldest / less useful SPA "pages").
I'm also assuming that having to manage memory for the SPA nav stack is also an unnecessary burden. Would that also be an interesting avenue as well?

--
Kenji BAHEUX
Product Manager - Chrome
Google Japan

Fergal Daly

unread,
Jun 1, 2021, 5:33:16 AM6/1/21
to Kenji Baheux, Vladimir Levin, Aditya Punjani, bfcache-dev
On Tue, 1 Jun 2021 at 16:20, 'Kenji Baheux' via bfcache-dev <bfcac...@chromium.org> wrote:
Hi Aditya,

Sorry for the delay!

I think we had been assuming that Back navigations in SPA, although tedious, didn't leave much room for performance opportunities.
But that was more of a hunch than backed by data. And, recently, I heard similar feedback from other SPA partners who didn't think that the performance of their back navigations was great/on-par with a native BFCache.

Do you have any info on what the performance problem is? I would guess at a couple of problems when going back in an SPA
- HTML for the old page is being regenerated - this could be solved by keeping the HTML around and use content-visibility to prevent it slowing down layout
- HTML for the old page was stored off in an invisible document and is swapped into the real document, causing a bit update to the DOM and also a layout as described below
- the old content is in the document but hidden with content-visibility and there's a large layout happening when it's made visible - it seems this could be optimized inside blink if the screen size has not changed between making the content invisible and making it visible again (if we don't already do this, I feel like we might - Vlad?)

The last one there seems like the current best possible case for an SPA and if we can remember the old layout an SPA back should be competitive with BFCache,

F

 

You mentioned that client side navigations still require a lot of javascript processing: could you share some numbers or annotated devtools traces ? (feel free to PM me if preferable)

In parallel to performance aspects, it also seems that an API would help the UA understand what's going on, and allow it to manage memory usage (e.g. evict the oldest / less useful SPA "pages").
I'm also assuming that having to manage memory for the SPA nav stack is also an unnecessary burden. Would that also be an interesting avenue as well?


On Fri, May 21, 2021 at 5:23 PM Aditya Punjani <aditya....@airbnb.com> wrote:
Hey folks, 

This is just a thought experiment but I was wondering what it would take to make some version of bfcache work for client side apps. Today bfcache works great for document navigations but is not useful in SPA client side navigations.

One of the most common use cases on the web is navigating back and forth between a search results page and various item pages from the search results. 

If we had an API like bfcache.pushState() and bfcache.popState() that could serialize the dom state of the search results page, then we client side navigate to an item page and on back instead of doing a client side navigation we just restore the serialized page from the bfcache. 

This would significantly improve performance in client side apps where client side navigations still require a lot of javascript processing.

Curious if anything along these lines would be feasible? 

Thanks,
Aditya


--
Kenji BAHEUX
Product Manager - Chrome
Google Japan

--
You received this message because you are subscribed to the Google Groups "bfcache-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to bfcache-dev...@chromium.org.
To view this discussion on the web, visit https://groups.google.com/a/chromium.org/d/msgid/bfcache-dev/CADWWn7UB8wEfa%2BXRkyXx4jY5KuGZiDsduigmzF1iKkjzPrhhMQ%40mail.gmail.com.

Max Chernyavskyi

unread,
Nov 1, 2023, 9:09:26 AM11/1/23
to bfcache-dev, Fergal Daly, Aditya Punjani, bfcache-dev, Kenji Baheux, Vladimir Levin
We're now in a paradoxical situation in which SPAs offer better user experience by executing URL changes with partial DOM updates, but traditional non-SPA sites are better at navigating back in history due to bfcache.

Consider this PLP https://www.asos.com/men/shoes-boots-trainers/cat/?cid=4209 , and suppose the user scrolls all the way down to the LOAD MORE cta, clicks it, scrolls a little bit more and then clicks on a product, then from the product page they click the back history button. It requires a colossal amount of development effort to return the user to the position in the PLP where they left off. Not only the number of `load more` clicks must be recorded in query param `page=2` (I don't see why this page depth needs to be reflected in the URL other than for the purpose onlined here), but the scroll position must be stored in a query param too. You can see it briefly flashing in the URL right after clicking on the product.

Shockingly, such experience with bfcache comes out of the box with no development effort at all, had the PLP and product pages been standalone html files. However, with separate html files, the whole page must be reloaded each time with no option of preserving the header or other elements across the two pages. 

You can see the described flow below:
spa-state-restoration.gif

I'm interested in any thoughts on how bfcache can be leveraged by SPAs for similar use cases.

Thanks,
Max

Vladimir Levin

unread,
Nov 1, 2023, 10:32:52 AM11/1/23
to Max Chernyavskyi, bfcache-dev, Fergal Daly, Aditya Punjani, Kenji Baheux
I agree with Fergal that it seems like we have enough primitives to solve the performance aspect of SPA navs, although perhaps not ergonomically. I wonder if there's something here we can do to help, like automatically doing the content-visibility thing to preserve rendering state somehow

As for the usability part, and what to record, it seems like in general we'd want to persist not just the DOM but also scroll positions and perhaps some script state as well? For MPA BFCache this is "easy" enough since we just cache the whole document. For SPA, however, the document itself is still used, so we need to store some snapshot of state. It's unclear to me whether we can use BFCache for this, or what it would mean for some state to be restored and some to remain live.

Thanks,
Vlad

Fergal Daly

unread,
Nov 1, 2023, 9:06:49 PM11/1/23
to Vladimir Levin, Max Chernyavskyi, bfcache-dev, Aditya Punjani, Kenji Baheux
On Wed, 1 Nov 2023 at 23:32, Vladimir Levin <vmp...@google.com> wrote:
I agree with Fergal that it seems like we have enough primitives to solve the performance aspect of SPA navs, although perhaps not ergonomically. I wonder if there's something here we can do to help, like automatically doing the content-visibility thing to preserve rendering state somehow

As for the usability part, and what to record, it seems like in general we'd want to persist not just the DOM but also scroll positions and perhaps some script state as well? For MPA BFCache this is "easy" enough since we just cache the whole document. For SPA, however, the document itself is still used, so we need to store some snapshot of state. It's unclear to me whether we can use BFCache for this, or what it would mean for some state to be restored and some to remain live.

Yeah, given that it's all the same document, I'm not sure any of BFCache's infrastructure can help. It depends heavily on these being separate renderers, e.g. it freezes the task queue for JS but in a single document that can't work.

Also BFCache is pretty non-deterministic, there are many things that can cause eviction. So when it's magic, it's magic but for example it will never be magic if more than 10 minutes has elapsed.

I don't know who SPAs typically handle this kind of thing but in the example you give, it's transitioning from one view to another and presumably discarding the old view entirely? I guess it could instead keep the DOM element with that view around and on navigating back, just plop it back in place. Maybe there's some support we could provide there to restore the scroll position automatically when a scrollable DOM element is reattached but it seems like it's doable within JS (restoring well after a resize seems tricky but  don't know if BFCache does a great job here either).

I can imagine allowing JS to add hints that certain elements, timers, tasks, network requests belong to a group that can be made (in)active although I'm not sure how much we can save vs currently by just detaching elements.

If we encourage SPAs to start hoarding inactive views, they need to start worrying about memory pressure.

F

Reply all
Reply to author
Forward
0 new messages