• Stars
    star
    154
  • Rank 242,095 (Top 5 %)
  • Language
    HTML
  • License
    Other
  • Created over 7 years ago
  • Updated about 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Lifecycle API to support system initiated discarding and freezing

Lifecycle API for Web Pages

Link to spec: https://wicg.github.io/page-lifecycle/

Motivation

For detailed motivation see this doc.

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 OS' manage resources. On Android, iOS and also more recent Windows versions, apps can be started and stopped at will by the platform. This lets the platform streamline and re-allocate resources where they best benefit the user.

On the web, weโ€™ve tackled this with one-off features eg. reactive tab-discarding in extreme memory pressure - which can break websites. While this is okay in the short term, in the long term it is important to incorporate first class support in the web platform, create the right incentive structure for web developers, and allow the system to proactively reallocate resources and avoid getting into extreme resource situations.

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

  • provide developers with signals about transitions between the lifecycle states
  • provide lifecycle-compatible APIs that allow key capabilities to work even when the app is backgrounded or stopped.

The web ecosystem lacks a clear lifecycle. This proposal attempts to define what the lifecycle of a web page is and add necessary extensions to enable supporting two important system interventions necessary for resource re-allocation:

  • Tab discarding for memory saving
  • CPU stopping for battery saving

Whereas mobile platforms have rich service-bound APIs that allow apps to deliver their experience when backgrounded, most of the web platform's capabilities are tab-coupled. Audio for instance only works when the tab is alive, so when a tab is killed in the background that plays audio, there is no way to keep that tab playing sound. A list of background use-cases is here. In an ideal world, web apps would be able to deliver the experience they want to their users, without having to rely on their page always being resident and running on the machine.

Lifecycle States

Lifecycle States

For details on the app lifecycle states and definitions see this doc.

This proposal formalizes states for FROZEN and DISCARDED.

Lifecycle State Visibility Developer Expectation System Interventions
FROZEN Typically HIDDEN frames will be FROZEN. It is possible for visible frames to be FROZEN Hand off for background work and stop execution. Teardown and release resources. Report to analytics CPU suspension: stop CPU after N minutes based on resource constraints
DISCARDED Typically FROZEN frames will be moved to DISCARDED. It is possible for PASSIVE frames to be DISCARDED System has discarded background tab to reclaim memory. If user revisits tab, this will reload the tab. Tab discarding for memory saving: fully unloaded, no memory consumption.
  • Lifecycle states apply to frames: both toplevel and nested.
  • When a background tab is transitioned to FROZEN, the entire frame tree will be consistently moved to FROZEN

End-of-life scenarios

There are 3 high level scenarios for โ€œend-of-lifeโ€.

1. System Exit (Interventions)

The system moves the app to FROZEN state and stops CPU usage, or the system moves the app to DISCARDED state and discards the app to reclaim memory. Handling this is in-scope for this proposal.
For detailed Scenarios and Requirements, see the list here.

On system exit, there is no guaranteed callback at the (very) time of system exit. This is consistent with mobile platforms (Android and iOS): in Android onPause is the guaranteed callback for user exit, on iOS the equivalent is willResignActive. On Android and iOS the system kills background apps that were previously stopped / frozen; corresponding callbacks have already fired and there is no callback before system kill.

2. User Exit

The user may close the tab (foreground or background) or navigate away OR on mobile, swipe the app away from task switcher. The user may background the app by minimizing the window OR on mobile by going to the homescreen and task switcher.
On user exit, the browser should guarantee that one callback will fire and finish, before the app is torn down.

For categories of work that happen in end-of-life see the list of End-of-life use-cases here.

3. Unexpected Termination

Apps can get killed in scenarios where it is not possible to deliver a callback, such as OOM crashes, OS kills the process under memory pressure, crashes or hangs due to browser bugs, device runs out of battery etc. Therefore it is possible for apps to transition from any state to TERMINATED without any callback being fired.\

It is not possible to have a guaranteed callback execute in most of these scenarios.

MVP API

Lifecycle Callbacks

We following changes are included in the MVP:

  • onfreeze is fired to signal transition to FROZEN.
  • onresume is fired to signal transition out of FROZEN. This will be used to undo what was done in onfreeze above.
  • On DISCARDED -> ACTIVE, an attribute called wasDiscarded is added to the Document. This will be used to restore view state , when the user revisits a discarded tab.
  • onfreeze is also fired before transition to BFCACHE (before pagehide is fired) and onresume is also fired on transition out of BFCACHE (after pageshow is fired).

Suggestion for implementers: before moving app to DISCARDED it is recommended to run beforeunload handler and if it returns string (i.e. needs to show modal dialog) then the tab discard should be omitted, to prevent risk of data loss.

Reusing existing callbacks vs. Adding new callbacks

A previous version of this proposal reused pagehide / pageshow callbacks. With the requirement that visible and occluded (ACTIVE & PASSIVE) frames can be FROZEN (not just HIDDEN frames), the cons really outweighed the pros of reusing. For detailed pros and cons see here.

Why add new callbacks at all?

Why cannot web apps simply use existing callbacks to deal with FROZEN and DISCARDED states? The callbacks are necessary for several reasons:

  • Teardown and setup of expensive resources such as IDB and Web Locks
  • Many apps rely on unload handler and no further callbacks are fired after onfreeze if the page is discarded. onfreeze provides a final callback for this need.
    • Apps that often have multiple tabs open, such as Google Docs, need to coordinate app state across these tabs. Such apps rely on getting a callback before the page goes away, eg. Google Docs needs to release their (custom) lock.
    • Final communication to the server
  • Platform predictability and transparency in the face of freezing & discarding interventions becoming the norm. Specifically helping:
    • Analytics
    • Testing story

For details see this section of detailed doc.

API

Additions to Document interface:

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

Handling transition to FROZEN:

function handleFreeze(e) {
   // Handle transition to FROZEN
}
document.addEventListener("freeze", handleFreeze);

OR
document.onfreeze = function() { โ€ฆ }

NOTE: subsequently the app may get discarded, without firing another callback.

Handling transition out of FROZEN:

function handleResume(e) {
    // handle state transition FROZEN -> ACTIVE
}
document.addEventListener("resume", handleResume);

OR
document.onresume = function() { โ€ฆ }

Handling of discarding, on next load:

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

Potential future addition

In the future, if frame-level freezing (i.e. freeze specific frames within a page) is pursued, then the API could be enhanced to indicate which frame tree is frozen.

// Indicate what is frozen exactly:
// a. partial frame tree starting with current frame
// b. partial frame tree starting with an ancestor frame
// c. entire page in background
// d. ...
enum FrameLevel { ... };

interface FreezeEvent {
    readonly attribute FrameLevel frameLevel;
}

Callbacks in State Transition Scenarios

  • A. System stops (CPU suspension) background tab; user revisits
    [HIDDEN] -------------> onfreeze [FROZEN]
    --(user revisit)----> onresume [ACTIVE]

  • B. System discards frozen tab; user revisits
    (previously called onfreeze----> [FROZEN]
    ----(tab discard)----> [DISCARDED]
    --(user revisit)----> [LOADING] -> (Document::wasDiscarded is set) [ACTIVE]

  • C. System discards background tab; user revisits
    [HIDDEN] ---(tab discard)------>
    onfreeze [FROZEN] ---(system tab discard)---> [DISCARDED]
    --(user revisit)----> [LOADING] -> (Document::wasDiscarded is set) [ACTIVE]

State Transition Lifecycle Callback Trigger Expected Developer Action
ACTIVE -> HIDDEN onvisibilitychange (hidden) (already exists) Desktop: tab is in background, or window is fully hidden; Mobile: user clicks on task switcher or homescreen stop UI work; persist app state; report to analytics
HIDDEN -> ACTIVE onvisibilitychange (visible) (already exists) User revisits background tab undo what was done above; report to analytics
HIDDEN -> FROZEN onfreeze System initiated CPU suspension; OR user navigate with bfcache report to analytics; teardown, release resources; hand off for background work and stop execution. Save transient UI state in case app is moved to DISCARDED.
FROZEN -> ACTIVE onresume user revisits FROZEN tab or navigates back (bfcache) undo what was done above; report to analytics
FROZEN -> DISCARDED (no callback) System initiated tab-discard (no advance warning here)
DISCARDED -> ACTIVE (Document::wasDiscarded is set) user revisits tab after system tab discard restore transient UI state

Restrictions and Capabilities in proposed callbacks

If excessive work is performed in the onfreeze callback fired on FROZEN, there is a cost to this in terms of resource consumption i.e. CPU, network. We need to strike a balance between enabling the system to move the app to FROZEN for conserving resources AND enabling the app to take action without consuming excessive resources in these callbacks. To accomplish this, the following will apply to the callback:

  • network activity will be disallowed, except for fetch keep-alive. This will allow final communication with server as well as meet needs of analytics.
  • upper time limit of 500ms (total wall time) will be imposed. If the time limit is exceeded, the page will be discarded (instead of being FROZEN)
  • legitimate async work like writing to IndexedDB will be supported. Current proposal for supporting this is here: w3c/IndexedDB#234.

Guarantess for end-of-life callbacks

What should be the โ€œguaranteedโ€ callback for the Web?

We should align with the mobile model (Android and iOS) on the web. For this we need to ensure the following:

  1. on user exit: only one callback is guaranteed to fire and complete
  2. on system exit: above callback should have already fired, yet another callback is not guaranteed to fire (guarantee is simply not possible in many cases)

For #1, ideally all apps will transition through PASSIVE state before they can be killed and potentially we could, in the future, introduce a new callback here -- that is guaranteed. In practice though, there is already a callback that is "somewhat guaranteed" - this is onvisibilitychange (there are bugs in browsers, causing it to not fire in some cases, and it is not really guaranteed on mobile). For instance on mobile web, if the user goes to the homescreen OR task-switcher and then swipes away, then onvisibilitychange (with visibilityState being set to hidden) will fire (on homescreen, task-switcher) no other callback is fired on swipe (unload, pagehide etc).

NOTE: On Android onvisibilitychange is called from the onStop method of Activity lifecycle which is NOT guaranteed to fire. If we added a callback for transition to PASSIVE (in the future), then it could be called from onPause method of Activity lifecycle - which is guaranteed to fire. Therefore adding a callback for PASSIVE state would be helpful for Android.

While unload callback is widely used, it is fundamentally unreliable, for instance it does not fire on mobile if user goes to task-switcher and then swipes. There are currently no plans to make unload more reliable. (The long term vision is to replace it with declarative APIs for desktop)

For #2, callback for FROZEN state is not guaranteed on user exit scenarios. On system exit scenarios, typically FROZEN callback (at least onvisibilitychange for sure) would have already fired previously BUT there is no guarantee that FROZEN callback must have fired.

Further Reading

For details on the following topics see the Master Doc:

More Repositories

1

webcomponents

Web Components specifications
HTML
4,360
star
2

import-maps

How to control the behavior of JavaScript imports
JavaScript
2,705
star
3

virtual-scroller

1,998
star
4

focus-visible

Polyfill for `:focus-visible`
JavaScript
1,607
star
5

webusb

Connecting hardware to the web.
Bikeshed
1,310
star
6

webpackage

Web packaging format
Go
1,231
star
7

EventListenerOptions

An extension to the DOM event pattern to allow authors to disable support for preventDefault
JavaScript
1,166
star
8

portals

A proposal for enabling seamless navigations between sites or pages
HTML
946
star
9

floc

This proposal has been replaced by the Topics API.
Makefile
934
star
10

inert

Polyfill for the inert attribute and property.
JavaScript
920
star
11

scheduling-apis

APIs for scheduling and controlling prioritized tasks.
HTML
909
star
12

view-transitions

811
star
13

file-system-access

Expose the file system on the userโ€™s device, so Web apps can interoperate with the userโ€™s native applications.
Bikeshed
658
star
14

background-sync

A design and spec for ServiceWorker-based background synchronization
HTML
639
star
15

ua-client-hints

Wouldn't it be nice if `User-Agent` was a (set of) client hints?
Bikeshed
590
star
16

scroll-to-text-fragment

Proposal to allow specifying a text snippet in a URL fragment
HTML
586
star
17

observable

Observable API proposal
Bikeshed
582
star
18

aom

Accessibility Object Model
HTML
567
star
19

kv-storage

[On hold] A proposal for an async key/value storage API for the web
550
star
20

turtledove

TURTLEDOVE
Bikeshed
526
star
21

navigation-api

The new navigation API provides a new interface for navigations and session history, with a focus on single-page application navigations.
Makefile
486
star
22

webmonetization

Proposed Web Monetization standard
HTML
461
star
23

trust-token-api

Trust Token API
Bikeshed
421
star
24

attribution-reporting-api

Attribution Reporting API
Bikeshed
360
star
25

direct-sockets

Direct Sockets API for the web platform
HTML
329
star
26

shape-detection-api

Detection of shapes (faces, QR codes) in images
Bikeshed
304
star
27

display-locking

A repository for the Display Locking spec
HTML
297
star
28

dbsc

Bikeshed
297
star
29

background-fetch

API proposal for background downloading/uploading
Shell
281
star
30

first-party-sets

Bikeshed
280
star
31

serial

Serial ports API for the platform.
HTML
256
star
32

resize-observer

This repository is no longer active. ResizeObserver has moved out of WICG into
HTML
255
star
33

priority-hints

A browser API to enable developers signal the priorities of the resources they need to download.
Bikeshed
249
star
34

sanitizer-api

Bikeshed
227
star
35

is-input-pending

HTML
221
star
36

proposals

A home for well-formed proposed incubations for the web platform. All proposals welcome.
216
star
37

spatial-navigation

Directional focus navigation with arrow keys
JavaScript
212
star
38

js-self-profiling

Proposal for a programmable JS profiling API for collecting JS profiles from real end-user environments
HTML
197
star
39

cq-usecases

Use cases and requirements for standardizing element queries.
HTML
184
star
40

isolated-web-apps

Repository for explainers and other documents related to the Isolated Web Apps proposal.
Bikeshed
182
star
41

visual-viewport

A proposal to add explicit APIs to the Web for querying and setting the visual viewport
HTML
177
star
42

interventions

A place for browsers and web developers to collaborate on user agent interventions.
176
star
43

frame-timing

Frame Timing API
HTML
170
star
44

layout-instability

A proposal for a Layout Instability specification
Makefile
158
star
45

nav-speculation

Proposal to enable privacy-enhanced preloading
HTML
154
star
46

speech-api

Web Speech API
Bikeshed
145
star
47

cookie-store

Asynchronous access to cookies from JavaScript
Bikeshed
143
star
48

construct-stylesheets

API for constructing CSS stylesheet objects
Bikeshed
137
star
49

webhid

Web API for accessing Human Interface Devices (HID)
HTML
137
star
50

color-api

A proposal and draft spec for a Color object for the Web Platform, loosely influenced by the Color.js work. Heavily WIP, if you landed here randomly, please move along.
HTML
132
star
51

fenced-frame

Proposal for a strong boundary between a page and its embedded content
Bikeshed
126
star
52

devtools-protocol

DevTools Protocol
JavaScript
120
star
53

sms-one-time-codes

A way to format SMS messages for use with browser autofill features such as HTMLโ€™s autocomplete=one-time-code.
Makefile
111
star
54

bundle-preloading

Bundles of multiple resources, to improve loading JS and the Web.
HTML
105
star
55

translation-api

A proposal for translator and language detector APIs
Bikeshed
104
star
56

privacy-preserving-ads

Privacy-Preserving Ads
HCL
100
star
57

manifest-incubations

Before install prompt API for installing web applications
HTML
99
star
58

window-controls-overlay

HTML
97
star
59

netinfo

HTML
95
star
60

compression-dictionary-transport

94
star
61

intrinsicsize-attribute

Proposal to add an intrinsicsize attribute to media elements
93
star
62

animation-worklet

๐Ÿšซ Old repository for AnimationWorklet specification โžก๏ธ New repository: https://github.com/w3c/css-houdini-drafts
Makefile
92
star
63

container-queries

HTML
91
star
64

local-peer-to-peer

โ†”๏ธ Proposal for local communication between browsers without the aid of a server.
Bikeshed
90
star
65

shared-storage

Explainer for proposed web platform Shared Storage API
Bikeshed
89
star
66

async-append

A way to create DOM and add it to the document without blocking the main thread.
HTML
87
star
67

indexed-db-observers

Prototyping and discussion around indexeddb observers.
WebIDL
84
star
68

canvas-formatted-text

HTML
82
star
69

file-handling

API for web applications to handle files
82
star
70

canvas-color-space

Proposed web platform feature to add color management, wide gamut and high bit-depth support to the <canvas> element.
79
star
71

local-font-access

Web API for enumerating fonts on the local system
Bikeshed
77
star
72

performance-measure-memory

performance.measureMemory API
HTML
77
star
73

digital-credentials

Digital Credentials, like driver's licenses
HTML
77
star
74

handwriting-recognition

Handwriting Recognition Web API Proposal
Bikeshed
75
star
75

web-app-launch

Web App Launch Handler
HTML
75
star
76

pwa-url-handler

72
star
77

ContentPerformancePolicy

A set of policies that a site guarantees to adhere to, browsers enforce, and embedders can count on.
HTML
72
star
78

starter-kit

A simple starter kit for incubations
JavaScript
72
star
79

css-parser-api

This is the repo where the CSS Houdini parser API will be worked on
HTML
71
star
80

close-watcher

A web API proposal for watching for close requests (e.g. Esc, Android back button, ...)
Makefile
71
star
81

eyedropper-api

HTML
69
star
82

idle-detection

A proposal for an idle detection and notification API for the web
Bikeshed
67
star
83

storage-foundation-api-explainer

Explainer showcasing a new web storage API, NativeIO
65
star
84

video-editing

65
star
85

uuid

UUID V4
63
star
86

client-hints-infrastructure

Specification for the Client Hints infrastructure - privacy preserving proactive content negotiation
Bikeshed
61
star
87

sparrow

60
star
88

private-network-access

HTML
58
star
89

element-timing

A proposal for an Element Timing specification.
Bikeshed
57
star
90

document-picture-in-picture

Bikeshed
56
star
91

video-rvfc

video.requestVideoFrameCallback() incubation
HTML
53
star
92

time-to-interactive

Repository for hosting TTI specification and discussions around it.
52
star
93

digital-goods

Bikeshed
50
star
94

soft-navigations

Heuristics to detect Single Page Apps soft navigations
Bikeshed
46
star
95

raw-clipboard-access

An explainer for the Raw Clipboard Access feature
44
star
96

storage-buckets

API proposal for managing multiple storage buckets
Bikeshed
43
star
97

pending-beacon

A better beaconing API
Bikeshed
43
star
98

admin

๐Ÿ‘‹ Ask your questions here! ๐Ÿ‘‹
HTML
42
star
99

web-smart-card

Repository for the Web Smart Card Explainer
HTML
42
star
100

web-preferences-api

The Web Preference API aims to provide a way for sites to override the value for a given user preference (e.g. color-scheme preference) in a way that fully integrates with existing Web APIs.
Bikeshed
41
star