Description
The design of navigation interception, especially after #46 lands, leads to a novel situation. Namely, you can perform a single-page app navigation which fails, by passing a rejected promise to event.respondWith()
. A somewhat-realistic example might be:
appHistory.addEventListener("navigate", e => {
e.respondWith((async () => {
const response = await fetch("https://nonexistant.invalid/some-data.json");
// ... etc ...
})());
});
// This will get intercepted and converted to a failure.
location.href = "/foo";
The current plan as of #46 is that, because of the issues discussed in #19, all such navigations will synchronously succeed, but then asynchronously fail. Roughly:
location.href
, the URL bar, etc. immediately start pointing to/foo
, as if you'd donehistory.pushState(null, null, "/foo")
.appHistory.current
, as well as the underlying session history model, gets pointed to a new history entry for/foo
.- Any forward history entries get thrown away.
- But then, once the browser sees that the promise is rejected, it "rolls back" the navigation:
- It sets
location.href
, the URL bar, etc. back to the original URL that initiated the navigation. appHistory.current
, as well as the previous session history model, navigates back to the previous session history entry.- The history entry for
/foo
created in step (2) gets thrown away. - The forward history entries thrown away in (3) remain dead.
- It sets
Is this the right model for when the navigate
handler tells us the navigation failed?
The main alternative, I think, is to do a lot less. I.e., do not try to provide a rollback; leave location.href
, the URL bar, etc. on /foo
. Instead just signal to the app (e.g. with an event on window.appHistory
and/or window.appHistory.current
) that the promise rejected, and have the app handle that. The app could do its own rollback, perhaps. Or it could display a literal error page, like it might for a server-side 404.
I'm kind of leaning toward this do-less model. What do people think?
The other alternative would be to go the route of (2) in #19 (comment), which would allow us to delay all the updating stuff until we're sure the promise fulfills. Then there would be no navigate-then-rollback; we'd just never move at all in a failure case.