Skip to content

Commit e28ac9f

Browse files
rakinadomenicmarcoscaceres
authored
Add non-"fully active" document handling guide (#317)
* Add non-"fully active" document handling guide As discussed in w3ctag/design-reviews#628, we want to improve support for BFCache/non-fully active documents, as we noticed that a lot of API specifications do not handle it well/explicitly. This change adds various guides and things to be aware of related to non-"fully active" documents, including gives various examples. We hope this will help future APIs to handle BFCache/on-"fully active" documents correctly by default. * Rewrite "discard" bit * Apply suggestions from code review Co-authored-by: Domenic Denicola <[email protected]> * Apply suggestions from review * Link to pattern * Add note about prerender * Link to discard definition * Link to Geolocation API's TR page. * Apply suggestions from code review Co-authored-by: Marcos Cáceres <[email protected]> * Do not leave document stale * prerender link * Use old link for prerender Co-authored-by: Domenic Denicola <[email protected]> Co-authored-by: Marcos Cáceres <[email protected]>
1 parent 6c67d67 commit e28ac9f

File tree

1 file changed

+178
-0
lines changed

1 file changed

+178
-0
lines changed

index.bs

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,184 @@ See also:
579579
* [Security and privacy are essential](https://www.w3.org/2001/tag/doc/ethical-web-principles/#privacy)
580580
* [What data does this specification expose to an origin?](https://www.w3.org/TR/security-privacy-questionnaire/#underlying-platform-data)
581581

582+
<h3 id="support-non-fully-active">Support non-"fully active" documents</h3>
583+
584+
After a user navigated away from a document,
585+
the document might be cached in a non-[=Document/fully active=] state,
586+
and might be reused when the user navigates back to the entry holding the document, which makes navigation fast for users.
587+
In browsers, this is known as the back/forward cache, or "<abbr title="back/forward cache">BFCache</abbr>" for short.
588+
In the past, many APIs have missed specifying support for non-[=Document/fully active=] documents,
589+
making them hard to support in various user agents to cache pages in the BFCache, effectively making the user experience of navigating back and forth less optimal.
590+
591+
To avoid this happening with your API,
592+
you should specify support for non-[=Document/fully active=] documents by following these guidelines:
593+
594+
Note: It is possible for a document to not become [=Document/fully active=] for other reasons not related to
595+
caching, such as when the iframe holding the document gets detached.
596+
Some advices below might not be relevant for those cases,
597+
since the document will never return to [=Document/fully active=] again.
598+
599+
<h4 id="gate-fully-active">Gate actions with [=Document/fully active=] checks</h4>
600+
601+
When performing actions that might update the state of a document,
602+
be aware that the document might not be [=Document/fully active=]
603+
and is considered as "non-existent" from the user's perspective.
604+
This means they should not receive updates or perform actions.
605+
606+
Note: It is possible for a [=Document/fully active=] document to be perceived as "non-existent" by users,
607+
such as when the document is [displaying prerendered content](https://jeremyroman.github.io/alternate-loading-modes/).
608+
These documents might behave differently than non-[=Document/fully active=] documents,
609+
and the guidelines here might not be applicable to them,
610+
as it is written only for handling non-[=Document/fully active=] documents.
611+
612+
In many cases,
613+
anything that happens while the document is not [=Document/fully active=]
614+
should be treated as if it never happened.
615+
If it makes more sense to "update" a document to ensure it does not hold stale information
616+
after it becomes [=Document/fully active=] again, consider the [[#listen-fully-active]] pattern below.
617+
<div class="example">
618+
APIs that periodically send information updates,
619+
such as Geolocation API's {{Geolocation/watchPosition()}}
620+
should not send updates if the document is no longer fully active.
621+
They also should not queue those updates to arrive later,
622+
and only resume sending updates when the document becomes active again,
623+
possibly sending one update with the latest information then.
624+
</div>
625+
626+
<h4 id="listen-fully-active">Listen for changes to [=Document/fully active=] status</h4>
627+
628+
When a document goes from [=Document/fully active=] to non-[=Document/fully active=],
629+
it should be treated similarly to the way discarded documents are treated.
630+
The document must not retain exclusive access to shared resources
631+
and must ensure that no new requests are issued
632+
and that connections that allow for new incoming requests are terminated.
633+
When a document goes from non-[=Document/fully active=] to [=Document/fully active=] again,
634+
it can restore connections if appropriate.
635+
636+
While web authors can manually do cleanup (e.g. release the resources, sever connections)
637+
from within the {{pagehide}} event and restore them from the {{pageshow}} event themselves,
638+
doing this automatically from the API design allows the document to be kept alive after navigation by default,
639+
and is more likely to lead to well-functioning web applications.
640+
641+
<div class="example">
642+
APIs that create live connections can pause/close the connection and possibly resume/reopen it later.
643+
It's also possible to let the connection stay open to complete existing ongoing requests,
644+
and later update the document with the result when it gets restored, if appropriate (e.g.
645+
resource loads).
646+
</div>
647+
<div class="example">
648+
APIs that hold non-exclusive resources
649+
may be able to release the resource when the document becomes not fully active,
650+
and re-acquire them when it becomes [=Document/fully active=] again
651+
(Screen Wake Lock API is already [doing](https://w3c.github.io/screen-wake-lock/#handling-document-loss-of-full-activity) the first part).
652+
</div>
653+
654+
Note: this might not be appropriate for all types of resources,
655+
e.g. if an exclusive lock is held,
656+
we cannot just release it and reacquire when [=Document/fully active=]
657+
since another page could then take that lock.
658+
If there is an API to signal to the page that this has happened,
659+
it may be acceptable but beware that if the only time this happens is with BFCache,
660+
then it's likely many pages are not prepared for it. If it is not possible to support BFCache,
661+
follow the [[#discard]] pattern described below.
662+
663+
Additionally, when a document becomes [=Document/fully active=] again,
664+
it can be useful to update it with the current state of the world,
665+
if anything has changed while it is in the non-[=Document/fully active=] state.
666+
However, care needs to be taken with events that occurred while in the BFCache.
667+
When not [=Document/fully active=], for some cases, all events should be dropped,
668+
in some the latest state should be delivered in a single event,
669+
in others it may be appropriate to queue events or deliver a combined event.
670+
The correct approach is case by case and should consider privacy,
671+
correctness, performance and ergonomics.
672+
673+
Note: Making sure the latest state is sent to a document that becomes
674+
[=Document/fully active=] again is especially important when retrofitting existing APIs.
675+
This is because current users of these APIs expect to always have the latest information.
676+
Dropping state updates can leave the document with stale information,
677+
which can lead to unexpected and hard-to-detect breakage of existing sites.
678+
679+
<div class="example">
680+
The {{gamepadconnected}} event
681+
can be sent to a document that becomes [=Document/fully active=] again
682+
if a gamepad is connected while the document is not [=Document/fully active=].
683+
If the gamepad was repeatedly connected and disconnected,
684+
only the final connected event should be delivered.
685+
(This is not specified yet, see [issue](https://github.com/w3c/gamepad/issues/149))
686+
</div>
687+
<div class="example">
688+
For geolocation or other physical sensors,
689+
no information about what happened while not [=Document/fully active=] should be delivered.
690+
The events should simply resume from when the document became [=Document/fully active=].
691+
However, these APIs should check the state when the document becomes [=Document/fully active=] again,
692+
to determine if a status update should be sent (e.g. is the current location far away from the
693+
location when the document becomes not fully active?), to ensure the document has the latest
694+
information, as guaranteed by the API normally.
695+
</div>
696+
<div class="example">
697+
For network connections or streams,
698+
the data received while not [=Document/fully active=] should be delivered only
699+
when the document becomes [=Document/fully active=] again,
700+
but whereas a stream might have created many events with a small amount of data each,
701+
it could be delivered as smaller number of events with more data in each.
702+
</div>
703+
704+
<h4 id="omit-non-fully-active">Omit non-[=Document/fully active=] documents from APIs that span multiple documents</h4>
705+
Non-[=Document/fully active=] documents should not be observable,
706+
so APIs should treat them as if they no longer exist.
707+
They should not be visible to the "outside world" through document-spanning APIs
708+
(e.g. {{Clients/matchAll()|clients.matchAll()}}, {{Window/opener|window.opener}}).
709+
710+
Note: This should be rare since cross-document-spanning APIs are themselves relatively rare.
711+
712+
<div class="example">
713+
{{BroadcastChannel}} [checks](https://html.spec.whatwg.org/multipage/web-messaging.html#broadcasting-to-other-browsing-contexts:fully-active) for [=Document/fully active=] before sending messages to other browsing contexts.
714+
</div>
715+
<div class="example">
716+
{{Clients/matchAll()|clients.matchAll()}}
717+
currently does not distinguish between [=Document/fully active=]
718+
and non-[=Document/fully active=] clients,
719+
but correct implementations should only return [=Document/fully active=] clients.
720+
(See [issue](https://github.com/w3c/ServiceWorker/issues/1594))
721+
</div>
722+
723+
<h4 id="discard">Discard non-[=Document/fully active=] documents for situations that can't be supported</h4>
724+
If supporting non-[=Document/fully active=] documents is not possible for certain cases,
725+
explicitly specify it by [=discard a document|discarding the document|=] if the situation happens after the user navigated away,
726+
or setting the document's [salvageable](https://html.spec.whatwg.org/multipage/browsing-the-web.html#concept-document-salvageable)
727+
bit to false if the situation happens before or during the navigation away from the document,
728+
to cause it to be automatically discarded after navigation.
729+
730+
Note: this should be rare and probably should only be used when retrofitting old APIs,
731+
as new APIs should always strive to work well with BFCache.
732+
733+
<div class="example">
734+
WebSockets [sets the salvageable bit to false](https://html.spec.whatwg.org/#unloading-documents:concept-document-salvageable-7) during unload.
735+
</div>
736+
<div class="example">
737+
Calling {{Clients/claim()|clients.claim()}}
738+
should not wait for non-[=Document/fully active=] clients,
739+
instead it should cause the non-[=Document/fully active=] client documents to be discarded.
740+
(This is currently not specified, see [issue](https://github.com/w3c/ServiceWorker/issues/1594))
741+
</div>
742+
743+
<h4 id="per-document-state">Be aware that per-document state/data might persist after navigation</h4>
744+
As a document might be reused even after navigation,
745+
be aware that tying something to a document's lifetime
746+
also means reusing it after navigations.
747+
If this is not desirable,
748+
consider listening to changes to the [=Document/fully active=] state
749+
and doing cleanup as necessary (see above).
750+
<div class=example>
751+
[=Sticky activation=] is determined by the "last activation timestamp",
752+
which is tied to a document.
753+
This means after a user triggers activation once on a document,
754+
the document will have sticky activation forever,
755+
even after the user navigated away and back to it again.
756+
Whether this should actually be reset when full activity is lost or not
757+
is still [under discussion](https://github.com/whatwg/html/issues/6588).
758+
</div>
759+
582760
<h2 id="html">HTML</h2>
583761

584762
This section details design principles for features which are exposed via HTML.

0 commit comments

Comments
 (0)