W3C

Page Lifecycle 1

Editor’s Draft,

Issue Tracking:
GitHub
Editors:
(Google)
(Google)

Abstract

This document defines an API that supports browsers' ability to manage lifecycle of web pages.

Status of this document

This section describes the status of this document at the time of its publication. Other documents may supersede this document. A list of current W3C publications and the latest revision of this technical report can be found in the W3C technical reports index at https://www.w3.org/TR/.

This document was published by the Web Performance Working Group as an Editors Draft. This document is intended to become a W3C Recommendation.

Feedback and comments on this specification are welcome, please send them to public-web-perf@w3.org (subscribe, archives) with %5Bpage-lifecycle%5D at the start of your email’s subject.

Publication as an Editors Draft does not imply endorsement by the W3C Membership. This is a draft document and may be updated, replaced or obsoleted by other documents at any time. It is inappropriate to cite this document as other than work in progress.

This document was produced by a group operating under the W3C Patent Policy. W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy.

This document is governed by the 1 February 2018 W3C Process Document.

1. Introduction

With large numbers of web apps (and tabs) running, critical resources such as memory, CPU, battery, network, etc. easily get oversubscribed, leading to a bad end user experience. Application lifecycle is a key way that modern OSs manage resources.

For a platform to support application lifecycle, it needs to:

This proposal attempts to define what the lifecycle of a web page is and add needed extensions to enable web applications to respond to two important lifecycle events commonly performed by user agents:

2. Page Lifecycle States

This spec defines what the lifecycle of a web page is and adds extensions to enable web applications to respond to two important lifecycle events commonly performed by user agents:

This spec formalizes two new lifecycle states to support the above:

TODO(panicker): Insert diagram

3. API

Page Lifecycle involves the following additions:

partial interface Document {
    attribute EventHandler onfreeze;
    attribute EventHandler onresume;
    readonly attribute boolean wasDiscarded;
};

The onfreeze and onresume attributes are event handler IDL attributes for the freeze and resume events, respectively.

The wasDiscarded attribute’s getter must return the value of this Document's discarded boolean.

NOTE: these APIs are added on Document, instead of on Window, for consistency with the Page Visibility API; we expect these APIs to be used in tandem with that existing one. [PAGE-VISIBILITY]

NOTE: In addition clientId and discardedClientId will be added to Window, to support restoring view state when user revisits a discarded page, causing a reload. We expect those to be used by code that reacts to these events.

3.1. Usage example

Example of handling freeze and resume:

const prepareForFreeze = () => {
  // Close any open IndexedDB connections.
  // Release any web locks.
  // Stop timers or polling.
};

const reInitializeApp = () => {
  // Restore IndexedDB connections.
  // Re-acquire any needed web locks.
  // Restart timers or polling.
};

document.addEventListener('freeze', prepareForFreeze);
document.addEventListener('resume', reInitializeApp);

Example of restoring view state after discard: A user could have multiple tabs open for the same app & URL. If they are both in the background and are both discarded, then the app would need to distinguish between the two tabs to restore the correct state. clientId and lastClientId on the Window can be used for this purpose.

// Persists state to IndexedDB, making sure to set the current value of
// `self.clientId` on the record, so it can be retrieved later using
// `getPersistedState()` (if the tab has to be reloaded after a discard).
const persistState = async (state) => {
  const record = {...state, cliendId: self.clientId};

  // Persist record to IndexedDB or SessionStorage....
}

// Retrieves the state record from IndexedDB based on the passed client ID.
const getPersistedState = async (clientId) => {
  // Lookup record in IndexedDB...
};

// If the tab was previously discarded, get the persisted state for the
// client ID of the discarded tab via `self.lastClientId`.
if (document.wasDiscarded) {
  getPersistedState(self.lastClientId);
}

4. Processing model

4.1. Modifications to the HTML Standard

4.1.1. HTML: task source

Each task source is classified as freezable or unfreezable.

All tasks queued on freezable task source are automatically freezable.

The freezable task sources are:

TODO(domenic): classify all existing task sources in the HTML spec; find out if other specs have defined any relevant task sources.

4.1.2. HTML: Unloading documents and History Traversal

When documents move into and out of bfcache they will transition its frozenness state to true and false respectively.

4.1.3. HTML: HTML Event Loop Processing Model

Step #1 currently ignores "tasks whose associated Documents are not fully active". Modify this clause to also ignore freezable tasks whose associated Document is in the frozen state.

4.1.4. HTML: Discarding browsing context

Rename the "discard" concept, for both browsing contexts and documents, to "destroy". This allows us to use the "discarded" terminology for the user-facing wasDiscarded attribute.

4.1.5. HTML: Modifications to Initialize the document

Before Step #3 add following:

If the browsing context was previously discarded, then set the Document's discarded boolean to true.

4.2. Additions to Page Lifecycle spec

4.2.1. FROZENNESS state

A document can be in one of the following FROZENNESS states:

The UA may choose to execute §4.2.2.1 Change frozenness of a top-level document with true in certain situations. For instance, if a browsing context is in the background or hidden, and a grace period has elapsed the UA could execute §4.2.2.1 Change frozenness of a top-level document with true to conserve resources and maintain the quality of the (foreground) user experience. Specific examples:

The UA will typically execute §4.2.2.1 Change frozenness of a top-level document with false when the user revisits that browsing context. In addition, the UA may choose to periodically execute §4.2.2.1 Change frozenness of a top-level document with false in the background, if plentiful resources are available.

4.2.2. Reacting to FROZENNESS state changes

4.2.2.1. Change frozenness of a top-level document
To change the frozenness of a top-level document passing in a document doc and frozenness state x (one of true, false):
  1. Assert: doc’s browsing context is a top-level browsing context.

  2. Execute §4.2.2.2 Change frozenness of document passing in doc and x.

  3. Let descendants be the list of the descendant browsing contexts of doc.

  4. For each browsing context b in descendants:

    1. Let d be the active document of b.

    2. Execute §4.2.2.2 Change frozenness of document passing in d and x.

4.2.2.2. Change frozenness of document
To change the frozenness of a document given a document doc and frozenness state x:
  1. If x is true:

    1. Set doc’s frozenness state to true.

    2. Fire an event named freeze at doc.

  2. Otherwise:

    1. Fire an event named resume at doc.

    2. Set doc’s frozenness state to false.

    NOTE: it is intentional that the ordering between event-firing and setting the state are different in the two cases above.

4.2.3. Discarding

Each Document has a discarded boolean, which is initially false.

To discard a browsing context, destroy the browsing context, and make note of the fact that the reason it and any descendant browsing contents were destroyed was because of discarding.

NOTE: Discard is typically done to reclaim system memory, when memory and other resources are running low. On the other hand destroying a browser context is the normal teardown due to user leaving the page etc.

Browsing contexts -- that are in the background and have their documents in VisibilityState hidden -- can be discarded, under resource pressure (eg. low memory). Specific example:

When a top-level browsing context (tab in the browser) is discarded due to resource pressure (or unexpected events eg. process crash), and later the user revisits the tab in the browser, then the Document's discarded boolean will be true due to §4.1.5 HTML: Modifications to Initialize the document.

5. Acknowledgements

Special thanks to Ojan Vafai, Philip Walton, Fadi Meawad, Olli Pettay, Todd Reifsteck for their technical input and suggestions that led to improvements to this specification.

Index

Terms defined by this specification

Terms defined by reference

References

Normative References

[DOM]
Anne van Kesteren. DOM Standard. Living Standard. URL: https://dom.spec.whatwg.org/
[HTML]
Anne van Kesteren; et al. HTML Standard. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[WebIDL]
Cameron McCormack; Boris Zbarsky; Tobie Langel. Web IDL. 15 December 2016. ED. URL: https://heycam.github.io/webidl/

Informative References

[PAGE-VISIBILITY]
Jatinder Mann; Arvind Jain. Page Visibility (Second Edition). 29 October 2013. REC. URL: https://www.w3.org/TR/page-visibility/

IDL Index

partial interface Document {
    attribute EventHandler onfreeze;
    attribute EventHandler onresume;
    readonly attribute boolean wasDiscarded;
};