Page Lifecycle

Draft Community Group Report,

This version:
https://wicg.github.io/page-lifecycle/
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 specification was published by the Web Platform Incubator Community Group. It is not a W3C Standard nor is it on the W3C Standards Track. Please note that under the W3C Community Contributor License Agreement (CLA) there is a limited opt-out and other conditions apply. Learn more about W3C Community and Business Groups.

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. Feature Policies

Controlling the execution state of nested browsing contexts is desirable from a browsing context in order to control the user experience. An application may desire that when a document is not being rendered or does not intersect the viewport that all execution stops in the nested browsing context (including currently playing video, audio). Stopping all execution can lead to an improvement in CPU utilization. To meet these needs, two feature policies are defined:

The "execution-while-not-rendered" policy controls whether tasks should execute for nested browsing contexts whose browsing context container is not being rendered.

The "execution-while-out-of-viewport" policy controls whether tasks should execute for nested browsing contexts whose browsing context container does not intersect the viewport according to compute the intersection of a target element and the root.

§ 5.2 Modifications to the HTML Standard accomplishes this by placing the document (and its decendants) in a frozen state when the following conditions have been met:

If these conditions aren’t met, the document will be in the unfrozen state.

<!-- The iframe will be frozen immediately after it is loaded. -->

<iframe allow="execution-while-not-rendered 'none'"
  src="subframe.html" style="display:none"></iframe>
To run the update document frozenness steps for a Document document:
  1. If document’s browsing context is not a nested browsing context, then return.

  2. If document’s readiness is not "complete", then return.

  3. Let element be document’s browsing context's browsing context container.

  4. Let frozenness be false.

  5. Let auto resume media be false.

  6. If document is not allowed to use the "execution-while-not-rendered" feature, then:

    1. If element is not being rendered, set frozenness to true.

  7. Otherwise if document is not allowed to use the "execution-while-out-of-viewport" feature, then:

    1. If element does not intersect the viewport according to compute the intersection of a target element and the root, set frozenness to true and set auto resume media to true.

  8. If frozenness does not equal document’s frozenness state, change the frozenness of a document given document, frozenness, and auto resume media.

5. Processing model

5.1. Modifications to worklet and worker behavior

Any worklet agent whose single realm's global object's owning document is frozen must become blocked. Any dedicated worker agent whose single realm's global object's owning document is non-null and frozen must become blocked.

To determine the owning document for a DedicatedWorkerGlobalScope workerGlobalScope:
  1. If workerGlobalScope’s owner set consists of a single Document document, then return document.

  2. If workerGlobalScope’s owner set consists of a single DedicatedWorkerGlobalScope parentWorkerGlobalScope, then return parentWorkerGlobalScope’s owning document.

  3. Return null.

NOTE: A DedicatedWorkerGlobalScope's owner set will always have exactly one item.

5.2. Modifications to the HTML Standard

5.2.1. Unloading documents and history traversal

When documents move into and out of bfcache (back forward cache) they will transition its frozenness state to true and false respectively.

5.2.2. Event loop: definitions

Replace: A task is runnable if its document if either null or fully active.

With: A task is runnable if its document is either null or fully active, and is also unfrozen.

5.2.3. Event loop: processing model

After Step #11 during the Update the rendering add the following step.

For each fully active Document doc in docs, run the update document frozenness steps given doc.

5.2.4. Discarding browsing contexts

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.

5.2.5. Initialize the document

Before Step #3 add following:

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

5.2.6. iframe load event steps

After Step #5 add following:

Run the update document frozenness steps given child document.

5.2.7. HTMLMediaElement

Each HTMLMediaElement has a resume frozen flag, which is initially set to false.

5.2.8. Posting messages

Add a note:

NOTE: When posting a message to a Window that is frozen, events that are queued on the posted message task source will not run until the Window is unfrozen. If too many events are queued, the user agent might discard the Window's browsing context (as part of the general allowance for discarding under resource pressure).

5.3. Modifications to the Service Worker Standard

5.3.1. Client

partial interface Client {
    readonly attribute ClientLifecycleState lifecycleState;
};

enum ClientLifecycleState {
    "active",
    "frozen"
};

A Client object has an associated lifecycle state, which is one of the ClientLifecycleState enumeration values.

5.3.1.1. lifecycleState

The lifecycleState attribute must return the context object's lifecycle state.

5.3.1.2. matchAll(options)

Rename variable in Step #4.

  1. Let matchedClientData be a new list.

Before Step #2.5.1 insert

  1. Let lifecycleState be the result of running Get Client Lifecycle State with client.

Append lifecycleState to list in Step #5.3.1

  1. Let windowData be «[ "client" → client, "ancestorOriginsList" → a new list, "lifecycleState" → lifecycleState ]».

Append lifecycleState to matchedClientData in Step #5.4

  1. Add «[ "client" → client, "lifecycleState" → lifecycleState ]» to matchedClientData.

Pass windowData lifecycleState into Create Window Client algorithm in Step #6.2

  1. Let windowClient be the result of running Create Window Client algorithm with windowData["client"], windowData["frameType"], windowData["visibilityState"], windowData["focusState"], windowData["ancestorOriginsList"], and windowData["lifecycleState"] as the arguments.

Adjust Step #6.3

  1. For each clientData in matchedClientData:

    1. Let clientObject be the result of running Create Client algorithm with clientData["client"], and clientData["lifecycleState"] as the arguments.

    2. Append clientObject to clientObjects.

5.3.1.3. openWindow(url)

Before Step #7.5 insert

  1. Let lifecycleState be the result of running Get Client Lifecycle State with context object's associated service worker client.

Adjust Step #7.8.2 to provide lifecycleState

  1. Let client be the result of running Create Window Client with newContext’s Window object’s environment settings object, frameType, visibilityState, focusState, ancestorOriginsList, and lifecycleState as the arguments.

5.3.2. Algorithms

5.3.2.1. Get Client Lifecycle State

Append the following algorithm:

Input

client, a service worker client

Output

state, a string

  1. Let state be "active".

  2. If client’s global object's owning document is frozen, set state to be "frozen"

  3. Return state.

5.3.2.2. Create Client

To Input append lifecycleState, a string

After Step #2 in Output append

  1. Set clientObject’s lifecycle state to lifecycleState.

5.3.2.3. Create Window Client

To Input append lifecycleState, a string

After Step #5 in Output append

  1. Set windowClient’s lifecycle state to lifecycleState.

5.4. Page lifecycle processing model

5.4.1. FROZENNESS state

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

The UA may choose to execute change the frozenness of a top-level document algorithm with true in certain situations. For instance, if a top level browsing context is in the background or hidden, and a grace period has elapsed the UA could execute change the 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 change the frozenness of a top-level document with false when the user revisits that browsing context. In addition, the UA may choose to periodically execute change the frozenness of a top-level document with false in the background, if plentiful resources are available.

5.4.2. Changing the frozenness of documents

To change the frozenness of a top-level document, given a Document topLevelDoc and boolean frozenness state frozenness:
  1. Assert: doc’s browsing context is a top-level browsing context.

  2. Change the frozenness of a document given topLevelDoc, frozenness, and false.

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

  4. For each browsing context b in descendants:

    1. Let descendantDocument be the active document of b.

    2. Change the frozenness of a document given descendantDocument, frozenness, and false.

To change the frozenness of a document, given a Document doc, a boolean frozenness state frozenness, and a boolean auto resume frozen media:
  1. If frozenness is true, run the freeze steps for doc given auto resume frozen media.

  2. Otherwise, run the resume steps given doc.

To run the freeze steps for a Document doc, given a boolean auto resume frozen media:
  1. Set doc’s frozenness state to true.

  2. Fire an event named freeze at doc.

  3. Let elements be all media elements that are shadow-including descendants of doc, in shadow-including tree order.

  4. For each element in elements:

    1. If element’s paused is false, then:

      1. Set element’s resume frozen flag to auto resume frozen media.

      2. Execute media pause on element.

    NOTE: it is intentional that the ordering between the assignment of the of frozneness state occurs first before event firing.

To run the resume steps for a Document doc:
  1. Let elements be all media elements that are shadow-including descendants of doc, in shadow-including tree order.

    1. For each element in elements:

      1. If elements’s resume frozen flag is true.

        1. Set elements’s resume frozen flag to false.

        2. Execute media play on element.

  2. Fire an event named resume at doc.

  3. Set doc’s frozenness state to false.

    NOTE: it is intentional that the ordering between the assignment of the of frozneness state comes last after event firing.

5.4.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 § 5.2.5 Initialize the document.

6. Acknowledgements

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

Conformance

Conformance requirements are expressed with a combination of descriptive assertions and RFC 2119 terminology. The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in the normative parts of this document are to be interpreted as described in RFC 2119. However, for readability, these words do not appear in all uppercase letters in this specification.

All of the text of this specification is normative except sections explicitly marked as non-normative, examples, and notes. [RFC2119]

Examples in this specification are introduced with the words “for example” or are set apart from the normative text with class="example", like this:

This is an example of an informative example.

Informative notes begin with the word “Note” and are set apart from the normative text with class="note", like this:

Note, this is an informative note.

Index

Terms defined by this specification

Terms defined by reference

References

Normative References

[CSS2]
Bert Bos; et al. Cascading Style Sheets Level 2 Revision 1 (CSS 2.1) Specification. URL: http://dev.w3.org/csswg/css2/
[DOM]
Anne van Kesteren. DOM Standard. Living Standard. URL: https://dom.spec.whatwg.org/
[FEATURE-POLICY-1]
Ian Clelland. Feature Policy. URL: https://w3c.github.io/webappsec-feature-policy/
[HTML]
Anne van Kesteren; et al. HTML Standard. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra Standard. Living Standard. URL: https://infra.spec.whatwg.org/
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. March 1997. Best Current Practice. URL: https://tools.ietf.org/html/rfc2119
[SERVICE-WORKERS-1]
Alex Russell; et al. Service Workers 1. URL: https://w3c.github.io/ServiceWorker/
[WebIDL]
Boris Zbarsky. Web IDL. 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;
};

partial interface Client {
    readonly attribute ClientLifecycleState lifecycleState;
};

enum ClientLifecycleState {
    "active",
    "frozen"
};