-
Notifications
You must be signed in to change notification settings - Fork 12
/
spec.bs
455 lines (329 loc) · 25.9 KB
/
spec.bs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
<pre class='metadata'>
Title: Page Lifecycle
Group: WICG
Status: CG-DRAFT
Shortname: page-lifecycle
Level: 1
URL: https://wicg.github.io/page-lifecycle/
Editor: Scott Haseley, Google https://google.com, shaseley@google.com
Former Editor: Shubhie Panicker, Google https://google.com, panicker@google.com
Former Editor: Domenic Denicola, Google https://google.com, d@domenic.me
Repository: wicg/page-lifecycle
Abstract: This document defines an API that supports browsers' ability to manage lifecycle of web pages.
Default Biblio Status: current
Markup Shorthands: markdown yes
</pre>
<pre class='link-defaults'>
spec:dom; type:interface; text:Document
spec:infra; type:dfn; text:list
</pre>
<pre class='anchors'>
spec: HTML; urlPrefix: https://html.spec.whatwg.org/multipage/;
type: attribute; text: persisted; for:PageTransitionEvent; url: browsing-the-web.html#dom-pagetransitionevent-persisted
type: dfn; text: traverse the history; url: browsing-the-web.html#traverse-the-history
type: dfn; text: list of the descendant browsing contexts; url: browsers.html#list-of-the-descendant-browsing-contexts
type: dfn; text: browsing context; for: document; url: browsers.html#concept-document-bc
type: dfn; text: readiness; for: document; url: dom.html#current-document-readiness
type: dfn; text: iframe load in progress; url: iframe-embed-object.html#iframe-load-in-progress
type: dfn; text: iframe load event steps; url: iframe-embed-object.html#iframe-load-event-steps
type: dfn; text: Update the rendering; url: webappapis.html#update-the-rendering
type: dfn; text: being rendered; url: rendering.html#being-rendered
type: dfn; text: browsing context container; url: browsers.html#browsing-context-container
type: dfn; text: media elements; url: media.html#media-element
type: dfn; text: media pause; url: media.html#internal-pause-steps
type: dfn; text: media play; url: media.html#internal-play-steps
type: dfn; text: dedicated worker agent; url: webappapis.html#dedicated-worker-agent
type: dfn; text: worklet agent; url: webappapis.html#worklet-agent
type: dfn; text: posted message task source; url: web-messaging.html#posted-message-task-source
spec: CSS2; urlPrefix: https://www.w3.org/TR/CSS2/
type: dfn; text: viewport; url: visuren.html#viewport
spec: IntersectionObserver; urlPrefix: https://w3c.github.io/IntersectionObserver/
type: dfn; text: compute the intersection of a target element and the root; url: #calculate-intersection-rect-algo
spec: ECMA262; urlPrefix: https://tc39.github.io/ecma262/;
type: dfn; text: blocked; url: #sec-forward-progress
type: dfn; text: realm; url: #sec-code-realms
spec: CSS-Houdini; urlPrefix: https://drafts.css-houdini.org/worklets;
type: dfn; text: owning document; for: worklet; url: #workletglobalscope-owner-document
spec: ServiceWorker; urlPrefix: https://w3c.github.io/ServiceWorker/
type: dfn; text: create window client; url: #create-windowclient-algorithm
type: dfn; text: create client; url: #create-client-algorithm
</pre>
Introduction {#intro}
=====================
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:
* 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.
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:
* Tab discarding (for memory saving)
* CPU suspension (for battery, data, CPU saving)
Page Lifecycle States {#sec-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:
* CPU suspension (for conserving battery, data, CPU)
* Tab discarding (for memory saving)
This spec formalizes two new lifecycle states to support the above:
* Frozen: lifecycle state for CPU suspension. This means that the [=freeze steps=] algorithm was called on the {{Document}}'s [=document/browsing context=]. Normally HIDDEN pages will be [=/frozen=] to conserve resources.
* Discarded: means that the [=discard=] algorithm was called on the {{Document}}'s [=document/browsing context=]. Normally [=/frozen=] frames will be moved to the discarded state to conserve resources.
TODO(panicker): Insert diagram
API {#sec-api}
=======================================
Page Lifecycle involves the following additions:
<pre class="idl">
partial interface Document {
attribute EventHandler onfreeze;
attribute EventHandler onresume;
readonly attribute boolean wasDiscarded;
};
</pre>
The <dfn attribute for="Document">onfreeze</dfn> and <dfn attribute for="Document">onresume</dfn> attributes are [=event handler IDL attributes=] for the <code>freeze</code> and <code>resume</code> events, respectively.
The <dfn attribute for="Document">wasDiscarded</dfn> attribute's getter must return the value of this {{Document}}'s [=Document/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 <a href="https://github.com/whatwg/html/issues/3378"><code>clientId</code> and <code>discardedClientId</code></a> 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.
Usage example {#example}
------------------------
Example of handling freeze and resume:
<pre class="example highlight" highlight="js">
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);
</pre>
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.
<pre class="example highlight" highlight="js">
// 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);
}
</pre>
Feature Policies {#feature-policies}
=====================
Controlling the execution state of [=nested browsing contexts=] is desirable from a [=document/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:
* "<dfn export><code>execution-while-not-rendered</code></dfn>", which has a [=default allowlist=] of <code>*</code>
* "<dfn export><code>execution-while-out-of-viewport</code></dfn>", which has a [=default allowlist=] of <code>*</code>
The "<a><code>execution-while-not-rendered</code></a>" policy controls whether
tasks should execute for [=nested browsing contexts=] whose [=browsing context container=] is not [=being rendered=].
The "<a><code>execution-while-out-of-viewport</code></a>" 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=].
[[#mod]] accomplishes this by placing the document (and its decendants) in a [=/frozen=] state when the following
conditions have been met:
* the [=iframe load event steps=] have been run;
* the policy is disabled for the document; and
* the relevant policy condition applies (not rendered or scrolled out of view).
If these conditions aren't met, the document will be in the [=/unfrozen=] state.
<pre class="example highlight" highlight="html">
<!-- The iframe will be frozen immediately after it is loaded. -->
<iframe allow="execution-while-not-rendered 'none'"
src="subframe.html" style="display:none"></iframe>
</pre>
<div algorithm>
To run the <dfn export>update document frozenness steps</dfn> for a {{Document}} |document|:
1. If |document|'s [=document/browsing context=] is not a [=nested browsing context=], then return.
1. If |document|'s [=document/readiness=] is not "<code>complete</code>", then return.
1. Let |element| be |document|'s [=document/browsing context=]'s [=browsing context container=].
1. Let |frozenness| be false.
1. Let |auto resume media| be false.
1. If |document| is not [=allowed to use=] the "<a><code>execution-while-not-rendered</code></a>" feature, then:
1. If |element| is not [=being rendered=], set |frozenness| to true.
1. Otherwise if |document| is not [=allowed to use=] the "<a><code>execution-while-out-of-viewport</code></a>" 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.
1. If |frozenness| does not equal |document|'s [=Document/frozenness=] state, [=change the frozenness of a document=] given |document|, |frozenness|, and |auto resume media|.
</div>
Processing model {#sec-processing-model}
========================================
Modifications to worklet and worker behavior {#worklets-workers}
----------------------------------------------------------------
Any [=worklet agent=] whose single [=/realm=]'s [=Realm/global object=]'s [=worklet/owning document=] is [=/frozen=] must become [=blocked=].
Any [=dedicated worker agent=] whose single [=/realm=]'s [=Realm/global object=]'s [=DedicatedWorkerGlobalScope/owning document=] is non-null and [=/frozen=] must become [=blocked=].
<div algorithm>
To determine the <dfn for="DedicatedWorkerGlobalScope" export>owning document</dfn> for a {{DedicatedWorkerGlobalScope}} |workerGlobalScope|:
1. If |workerGlobalScope|'s [=owner set=] consists of a single {{Document}} |document|, then return |document|.
1. If |workerGlobalScope|'s [=owner set=] consists of a single {{DedicatedWorkerGlobalScope}} |parentWorkerGlobalScope|, then return |parentWorkerGlobalScope|'s [=owning document=].
1. Return null.
NOTE: A {{DedicatedWorkerGlobalScope}}'s [=owner set=] will always have exactly one item.
</div>
Modifications to the HTML Standard {#mod}
--------------------------------------------
### <a href="https://html.spec.whatwg.org/multipage/browsing-the-web.html#unloading-documents">Unloading documents</a> and <a href="https://html.spec.whatwg.org/multipage/browsing-the-web.html#history-traversal">history traversal</a> ### {#html-bfcache-dfn}
When documents move into and out of <a href="https://webkit.org/blog/427/webkit-page-cache-i-the-basics/">bfcache (back forward cache)</a> they will transition its [=Document/frozenness=] state to true and false respectively.
* In the [=unload a document=] algorithm, after Step #5, if the {{PageTransitionEvent/persisted}} attribute is true (i.e. we are moving to bfcache), [=change the frozenness of a document=], given |document| and true.
* In the [=traverse the history=] algorithm, before Step #4.6.4, if the {{PageTransitionEvent/persisted}} attribute is true (i.e. we are moving out of bfcache), [=change the frozenness of a document=], given |document| and false.
### <a href="https://html.spec.whatwg.org/multipage/webappapis.html#definitions-3">Event loop: definitions</a> ### {#html-html-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=].
### <a href="https://html.spec.whatwg.org/multipage/webappapis.html#event-loop-processing-model">Event loop: processing model</a> ### {#html-event-loop}
After Step #11 during the [=Update the rendering=] add the following step.
For each [=fully active=] {{Document}} |doc| in <var ignore>docs</var>, run the [=update document frozenness steps=] given |doc|.
### <a href="https://html.spec.whatwg.org/multipage/window-object.html#a-browsing-context-is-discarded">Discarding browsing contexts</a> ### {#html-discarding}
Rename the "<a href="https://html.spec.whatwg.org/multipage/window-object.html#a-browsing-context-is-discarded">discard</a>" concept, for both browsing contexts and documents, to "destroy". This allows us to use the "discarded" terminology for the user-facing {{Document/wasDiscarded}} attribute.
### <a href="https://html.spec.whatwg.org/multipage/browsing-the-web.html#initialise-the-document-object">Initialize the document</a> ### {#html-initialize-doc}
Before Step #3 add following:
If the browsing context was previously [=/discarded=], then set the {{Document}}'s [=Document/discarded=] boolean to true.
### [=iframe load event steps=] ### {#html-iframe-load}
After Step #5 add following:
Run the [=update document frozenness steps=] given <var ignore>child document</var>.
### {{HTMLMediaElement}} ### {#html-media-elements}
Each {{HTMLMediaElement}} has a <dfn for="HTMLMediaElement">resume frozen flag</dfn>, which is initially set to false.
### <a href="https://html.spec.whatwg.org/multipage/web-messaging.html#posting-messages">Posting messages</a> ### {#html-post-message}
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 [=Window/browsing context=] (as part of the general allowance for discarding under resource pressure).
Modifications to the Service Worker Standard {#serviceworker-mod}
--------------------------------------------
### <a href="https://w3c.github.io/ServiceWorker/#client-interface">`Client`</a> ### {#serviceworker-client-dfn}
<pre class="idl">
partial interface Client {
readonly attribute ClientLifecycleState lifecycleState;
};
enum ClientLifecycleState {
"active",
"frozen"
};
</pre>
A {{Client}} object has an associated <dfn id="dfn-service-worker-client-lifecycle-state" for="Client">lifecycle state</dfn>, which is one of the {{ClientLifecycleState}} enumeration values.
#### {{ServiceWorkerClient/lifecycleState}} #### {#service-worker-client-lifecycle-state}
The <dfn attribute for="ServiceWorkerClient">lifecycleState</dfn> getter steps are to return [=this=]'s [=Client/lifecycle state=].
#### <a href="https://w3c.github.io/ServiceWorker/#clients-matchall">`matchAll(options)`</a> #### {#serviceworker-matchall-dfn}
Rename variable in Step #4.
1. Let |matchedClientData| be a new [=/list=].
Before Step #2.5.1 insert
1. Let <var ignore>lifecycleState</var> be the result of running [=Get Client Lifecycle State=] with <var ignore>client</var>.
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 <var ignore>windowClient</var> 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. [=list/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.
1. [=list/Append=] |clientObject| to <var ignore>clientObjects</var>.
#### <a href="https://w3c.github.io/ServiceWorker/#dom-clients-openwindow">`openWindow(url)`</a> #### {#serviceworker-openwindow-dfn}
Before Step #7.5 insert
1. Let |lifecycleState| be the result of running [=Get Client Lifecycle State=] with [=this=]'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 <var ignore>newContext</var>'s {{Window}} object's [=environment settings object=], <var ignore>frameType</var>, <var ignore>visibilityState</var>, <var ignore>focusState</var>, <var ignore>ancestorOriginsList</var>, and |lifecycleState| as the arguments.
### <a href="https://w3c.github.io/ServiceWorker/#algorithms">Algorithms</a> ### {#serviceworker-algorithms-dfn}
<section algorithm>
#### <dfn>Get Client Lifecycle State</dfn> #### {#get-client-lifecycle-state-algorithm}
Append the following algorithm:
: Input
:: |client|, a [=/service worker client=]
: Output
:: |state|, a string
1. Let |state| be {{ClientLifecycleState/"active"}}.
1. If |client|'s [=environment settings object/global object=]'s [=owning document=] is [=frozen=], set |state| to be {{ClientLifecycleState/"frozen"}}
1. Return |state|.
</section>
<section algorithm="create-client-monkeypatch">
#### <a href="https://w3c.github.io/ServiceWorker/#create-client-algorithm">Create Client</a> #### {#serviceworker-createclient-dfn}
To Input append
|lifecycleState|, a string
After Step #2 in Output append
1. Set <var ignore>clientObject</var>'s [=Client/lifecycle state=] to |lifecycleState|.
</section>
<section algorithm="create-window-client-monkeypatch">
#### <a href="https://w3c.github.io/ServiceWorker/#create-windowclient-algorithm">Create Window Client</a> #### {#serviceworker-createwindowclient-dfn}
To Input append
|lifecycleState|, a string
After Step #5 in Output append
1. Set <var ignore>windowClient</var>'s [=Client/lifecycle state=] to |lifecycleState|.
</section>
Page lifecycle processing model {#page-lifecycle}
--------------------------------------------
<h4 id="frozenness-state">FROZENNESS state</h4>
A document can be in one of the following <dfn for="Document">FROZENNESS</dfn> states:
* true: the document is <dfn export lt="frozen">frozen</dfn>, any tasks associated with the document will not run
* false: the document is <dfn export lt="unfrozen">unfrozen</dfn>, tasks associated with the document will run as usual
NOTE: Per the [=change the frozenness of a top-level document=] algorithm, when the Document of the top level browsing context changes its [=Document/frozenness=] state then all documents of descendant browsing contexts will also change [=Document/frozenness=] to the same value (and be consistent with the Document of the top level browsing context).
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:
* In mobile Chrome, tabs that have been in background for (at least) 5 minutes, may be [=/frozen=], to conserve battery and data.
* In desktop Chrome, background tabs that are not important to the user (not used in some time) may be [=/discarded=], to conserve memory
NOTE: background tabs that are actively doing work on behalf of the user (eg. playing audio) are generally not [=/frozen=] or [=/discarded=].
NOTE: For a detailed list of heuristics & exclusions used by Chrome, see <a href=https://docs.google.com/document/d/1QJpuBTdllLVflMJSov0tlFX3e3yfSfd_-al2IBavbQM/edit>this doc</a>.
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.
<h4 id="changing-frozenness">Changing the frozenness of documents</h4>
<div algorithm>
To <dfn>change the frozenness of a top-level document</dfn>, given a {{Document}} |topLevelDoc| and boolean [=Document/frozenness=] state |frozenness|:
1. Assert: |doc|'s [=Document/browsing context=] is a [=top-level browsing context=].
1. [=Change the frozenness of a document=] given |topLevelDoc|, |frozenness|, and false.
1. Let |descendants| be the [=list of the descendant browsing contexts=] of |doc|.
1. For each [=/browsing context=] |b| in |descendants|:
1. Let |descendantDocument| be the [=active document=] of |b|.
1. [=Change the frozenness of a document=] given |descendantDocument|, |frozenness|, and false.
</div>
<div algorithm>
To <dfn>change the frozenness of a document</dfn>, given a {{Document}} |doc|, a boolean [=Document/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|.
1. Otherwise, run the [=resume steps=] given |doc|.
</div>
<div algorithm>
To run the <dfn>freeze steps</dfn> for a {{Document}} <var>doc</var>, given a boolean |auto resume frozen media|:
1. Set |doc|'s [=Document/frozenness=] state to true.
1. [=Fire an event=] named <code>freeze</code> at |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 |element|'s {{HTMLMediaElement/paused}} is false, then:
1. Set |element|'s [=HTMLMediaElement/resume frozen flag=] to |auto resume frozen media|.
1. 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.
</div>
<div algorithm>
To run the <dfn export>resume steps</dfn> for a {{Document}} <var>doc</var>:
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 [=HTMLMediaElement/resume frozen flag=] is true.
1. Set |elements|'s [=HTMLMediaElement/resume frozen flag=] to false.
1. Execute [=media play=] on |element|.
1. [=Fire an event=] named <code>resume</code> at |doc|.
1. Set |doc|'s [=Document/frozenness=] state to false.
NOTE: it is intentional that the ordering between the assignment of the of frozneness state
comes last after event firing.
</div>
<h4 id="discarding">Discarding</h4>
Each Document has a <dfn for="Document">discarded</dfn> boolean, which is initially false.
To <dfn export lt="discarded|discard">discard</dfn> a browsing context, <a href="https://html.spec.whatwg.org/multipage/window-object.html#a-browsing-context-is-discarded">destroy the browsing context</a>, 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 <a href="https://www.w3.org/TR/page-visibility-2/#visibility-states-and-the-visibilitystate-enum">VisibilityState hidden</a> -- can be [=/discarded=], under resource pressure (eg. low memory). Specific example:
* In desktop Chrome, background tabs that are not important to the user (not used in some time) may be [=/discarded=], to conserve memory
NOTE: background tabs that are actively doing work on behalf of the user (eg. playing audio) are generally not [=/discarded=].
NOTE: For a detailed list of heuristics & exclusions used by Chrome, see <a href=https://docs.google.com/document/d/1QJpuBTdllLVflMJSov0tlFX3e3yfSfd_-al2IBavbQM/edit>this doc</a>.
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 [=Document/discarded=] boolean will be true due to [[#html-initialize-doc]].
<!-- ============================================================ -->
<h2 id=acknowledgements>Acknowledgements</h2>
<!-- ============================================================ -->
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.