페이지 라이프사이클

커뮤니티 그룹 초안 보고서,

이 버전:
https://wicg.github.io/page-lifecycle/
이슈 추적:
GitHub
편집자:
(Google)
이전 편집자:
(Google)
(Google)

요약

이 문서는 브라우저가 웹 페이지의 라이프사이클을 관리할 수 있도록 지원하는 API를 정의합니다.

이 문서의 상태

이 명세는 웹 플랫폼 인큐베이터 커뮤니티 그룹에서 발행되었습니다. W3C 표준이 아니며 W3C 표준 트랙에도 포함되어 있지 않습니다. W3C 커뮤니티 기여자 라이선스 계약 (CLA)에 따라 제한적 옵트아웃 및 기타 조건이 적용됩니다. W3C 커뮤니티 및 비즈니스 그룹에 대해 더 알아보세요.

1. 소개

많은 웹 앱(및 탭)이 실행 중일 때, 메모리, CPU, 배터리, 네트워크 등과 같은 중요한 리소스가 쉽게 과부하되어 최종 사용자 경험이 나빠집니다. 애플리케이션 라이프사이클은 현대 OS가 리소스를 관리하는 핵심 방법입니다.

플랫폼이 애플리케이션 라이프사이클을 지원하려면, 다음을 제공해야 합니다:

이 제안서는 웹 페이지의 라이프사이클이 무엇인지 정의하고, 사용자 에이전트가 흔히 수행하는 두 가지 주요 라이프사이클 이벤트에 웹 애플리케이션이 대응할 수 있도록 필요한 확장을 추가합니다:

2. 페이지 라이프사이클 상태

이 명세는 웹 페이지의 라이프사이클이 무엇인지 정의하고, 사용자 에이전트가 흔히 수행하는 두 가지 주요 라이프사이클 이벤트에 웹 애플리케이션이 대응할 수 있도록 확장을 추가합니다:

이 명세는 위 기능을 지원하기 위해 두 가지 새로운 라이프사이클 상태를 공식화합니다:

TODO(panicker): 다이어그램 삽입

3. API

페이지 라이프사이클은 다음과 같은 추가 기능을 포함합니다:

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

onfreezeonresume 속성은 각각 freezeresume 이벤트에 대한 이벤트 핸들러 IDL 속성입니다.

wasDiscarded 속성의 getter는 해당 Documentdiscarded 불리언 값을 반환해야 합니다.

참고: 이 API들은 Document에 추가되며, Window가 아닌 이유는 Page Visibility API와의 일관성을 위해서입니다. 이 API들은 기존 Page Visibility API와 함께 사용될 것으로 기대합니다. [PAGE-VISIBILITY]

참고: 추가로 clientIddiscardedClientIdWindow에 추가되어, 사용자가 discarded 페이지를 다시 방문해 리로드될 때 뷰 상태 복원을 지원합니다. 이러한 값들은 해당 이벤트에 반응하는 코드에서 활용될 것으로 예상합니다.

3.1. 사용 예시

freeze와 resume을 처리하는 예시:

const prepareForFreeze = () => {
  // 열린 IndexedDB 연결 닫기
  // 웹락 해제
  // 타이머 또는 폴링 중지
};

const reInitializeApp = () => {
  // IndexedDB 연결 복원
  // 필요한 웹락 재획득
  // 타이머 또는 폴링 재시작
};

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

discard 이후 뷰 상태 복원 예시: 사용자가 동일 앱 및 URL로 여러 탭을 열어둔 경우, 둘 다 백그라운드 상태에서 discarded 된다면 앱은 올바른 상태 복원을 위해 두 탭을 구분해야 합니다. Window의 clientId 및 lastClientId는 이러한 용도로 사용할 수 있습니다.

// 현재 self.clientId 값을 record에 저장해서,
// 이후 getPersistedState()로 탭이 discard 후 reload될 때 복원할 수 있도록 IndexedDB에 상태를 저장
const persistState = async (state) => {
  const record = {...state, cliendId: self.clientId};

  // record를 IndexedDB 또는 SessionStorage에 영속화...
}

// 전달된 client ID로 IndexedDB에서 상태 record를 조회
const getPersistedState = async (clientId) => {
  // IndexedDB에서 record 조회...
};

// 탭이 이전에 discard된 경우, self.lastClientId로 해당 client ID의 상태를 복원
if (document.wasDiscarded) {
  getPersistedState(self.lastClientId);
}

4. 기능 정책

중첩 브라우징 컨텍스트의 실행 상태를 제어하는 것은 브라우징 컨텍스트에서 사용자 경험을 제어하기 위해 바람직합니다. 애플리케이션은 문서가 렌더링 중이 아니거나 뷰포트와 교차하지 않을 때, 중첩 브라우징 컨텍스트(재생 중인 비디오, 오디오 포함)의 모든 실행을 중단시키고 싶을 수 있습니다. 모든 실행을 중단하면 CPU 사용량이 개선될 수 있습니다. 이를 위해 두 가지 기능 정책이 정의됩니다:

"execution-while-not-rendered" 정책은 중첩 브라우징 컨텍스트브라우징 컨텍스트 컨테이너렌더링 중이 아닌지에 대해 태스크 실행 여부를 제어합니다.

"execution-while-out-of-viewport" 정책은 중첩 브라우징 컨텍스트브라우징 컨텍스트 컨테이너뷰포트와 교차하지 않는지 대상 요소와 루트의 교차 영역 계산에 따라 태스크 실행 여부를 제어합니다.

§ 5.2 HTML 표준 수정에서는 다음 조건을 모두 만족할 때 문서(및 자손)를 frozen 상태로 둡니다:

이 조건이 만족되지 않으면 문서는 unfrozen 상태가 됩니다.

<!-- iframe은 로드 직후 frozen 상태가 됩니다. -->

<iframe allow="execution-while-not-rendered 'none'"
  src="subframe.html" style="display:none"></iframe>
Document document에 대해 문서 frozenness 갱신 단계를 실행하려면:
  1. document브라우징 컨텍스트중첩 브라우징 컨텍스트가 아니면 return.

  2. documentreadiness가 "complete"가 아니면 return.

  3. elementdocument브라우징 컨텍스트브라우징 컨텍스트 컨테이너로 설정.

  4. frozenness를 false로 설정.

  5. auto resume media를 false로 설정.

  6. document가 "execution-while-not-rendered" 기능을 사용할 수 없으면:

    1. element렌더링 중이 아니면 frozenness를 true로 설정.

  7. 그 외에 document가 "execution-while-out-of-viewport" 기능을 사용할 수 없으면:

    1. element뷰포트와 교차하지 않으면 교차 영역 계산에 따라 frozenness를 true, auto resume media를 true로 설정.

  8. frozennessdocumentfrozenness 상태와 다르면, 문서 frozenness 변경document, frozenness, auto resume media로 실행.

5. 처리 모델

5.1. 워크렛 및 워커 동작 수정

단일 realmworklet agentglobal objectowning documentfrozen이면 blocked가 되어야 합니다. 단일 dedicated worker agentrealmglobal objectowning document가 null이 아니고 frozen이면 blocked가 되어야 합니다.

DedicatedWorkerGlobalScope workerGlobalScopeowning document 결정 방법:
  1. workerGlobalScopeowner set에 단일 Document document만 있으면 document 반환.

  2. workerGlobalScopeowner set에 단일 DedicatedWorkerGlobalScope parentWorkerGlobalScope만 있으면 parentWorkerGlobalScopeowning document 반환.

  3. null 반환.

참고: DedicatedWorkerGlobalScopeowner set은 항상 정확히 1개의 항목만 가집니다.

5.2. HTML 표준 수정

5.2.1. 문서 언로딩히스토리 트래버설

문서가 bfcache(back forward cache)로 이동하거나 복귀할 때 각각 frozenness 상태를 true, false로 전환합니다.

5.2.2. 이벤트 루프: 정의

교체: task는 해당 document가 null이거나 fully active일 때 실행 가능하다.

변경 후: task는 해당 document가 null이거나 fully active이고, 또한 unfrozen 상태여야 실행 가능하다.

5.2.3. 이벤트 루프: 처리 모델

렌더링 업데이트 중 Step #11 이후에 다음 단계를 추가한다.

fully active Document docdocs에 있을 때, update document frozenness stepsdoc에 대해 실행한다.

5.2.4. 브라우징 컨텍스트 디스카드

브라우징 컨텍스트와 문서 모두에 대해 "discard" 개념의 이름을 "destroy"로 변경한다. 이렇게 하면 사용자에게 표시되는 wasDiscarded 속성에 "discarded" 용어를 사용할 수 있다.

5.2.5. 문서 초기화

Step #3 이전에 다음을 추가한다:

브라우징 컨텍스트가 이전에 discarded 상태였으면, 해당 Documentdiscarded 불리언을 true로 설정한다.

5.2.6. iframe load 이벤트 단계

Step #5 이후에 다음을 추가한다:

child document에 대해 update document frozenness steps를 실행한다.

5.2.7. HTMLMediaElement

HTMLMediaElementresume frozen flag를 가지며, 초기값은 false이다.

5.2.8. 메시지 전송

다음 참고를 추가한다:

참고: frozen 상태의 Window로 메시지를 전송할 때, posted message task source에 대기 중인 이벤트들은 Windowunfrozen 상태가 될 때까지 실행되지 않는다. 이벤트 대기열이 너무 많아지면, 사용자 에이전트는 Window브라우징 컨텍스트를 디스카드(리소스 압박 상황에서 일반적으로 허용되는 디스카드의 일부로)할 수 있다.

5.3. Service Worker 표준 수정

5.3.1. Client

partial interface Client {
    readonly attribute ClientLifecycleState lifecycleState;
};

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

Client 객체는 라이프사이클 상태를 가지고 있으며, 이는 ClientLifecycleState 열거형 값 중 하나입니다.

5.3.1.1. lifecycleState

lifecycleState getter 단계는 this라이프사이클 상태를 반환하는 것입니다.

5.3.1.2. matchAll(options)

Step #4에서 변수명을 변경합니다.

  1. matchedClientData를 새로운 리스트로 설정합니다.

Step #2.5.1 이전에 다음을 삽입합니다.

  1. lifecycleStateGet Client Lifecycle Stateclient와 함께 실행한 결과로 설정합니다.

Step #5.3.1에서 리스트에 lifecycleState를 추가합니다.

  1. windowData를 «[ "client" → client, "ancestorOriginsList" → 새로운 리스트, "lifecycleState" → lifecycleState ]»로 설정합니다.

Step #5.4에서 matchedClientData에 lifecycleState를 추가합니다.

  1. «[ "client" → client, "lifecycleState" → lifecycleState ]»를 matchedClientData에 추가합니다.

Step #6.2에서 windowData의 lifecycleState를 Create Window Client 알고리즘에 전달합니다.

  1. windowClientCreate Window Client 알고리즘을 windowData["client"], windowData["frameType"], windowData["visibilityState"], windowData["focusState"], windowData["ancestorOriginsList"], windowData["lifecycleState"]를 인자로 하여 실행한 결과로 설정합니다.

Step #6.3을 조정합니다.

  1. clientDatamatchedClientData에서 반복:

    1. clientObjectCreate Client 알고리즘을 clientData["client"], clientData["lifecycleState"]로 실행한 결과로 설정합니다.

    2. clientObjectclientObjects에 추가합니다.

5.3.1.3. openWindow(url)

Step #7.5 이전에 다음을 삽입합니다.

  1. lifecycleStateGet Client Lifecycle Statethis의 연결된 service worker client와 함께 실행한 결과로 설정합니다.

Step #7.8.2에서 lifecycleState를 제공하도록 조정합니다.

  1. clientCreate Window ClientnewContextWindow 객체의 environment settings object, frameType, visibilityState, focusState, ancestorOriginsList, lifecycleState를 인자로 하여 실행한 결과로 설정합니다.

5.3.2. 알고리즘

5.3.2.1. 클라이언트 라이프사이클 상태 가져오기

다음 알고리즘을 추가합니다:

입력

client, service worker client

출력

state, 문자열

  1. state"active"로 설정합니다.

  2. clientglobal objectowning documentfrozen이면 state"frozen"으로 설정합니다.

  3. state를 반환합니다.

5.3.2.2. 클라이언트 생성

입력에 lifecycleState (문자열)을 추가합니다.

출력의 Step #2 이후에 다음을 추가합니다.

  1. clientObject라이프사이클 상태lifecycleState로 설정합니다.

5.3.2.3. Window 클라이언트 생성

입력에 lifecycleState (문자열)을 추가합니다.

출력의 Step #5 이후에 다음을 추가합니다.

  1. windowClient라이프사이클 상태lifecycleState로 설정합니다.

5.4. 페이지 라이프사이클 처리 모델

5.4.1. FROZENNESS 상태

Document는 아래 FROZENNESS 상태 중 하나일 수 있습니다:

UA는 특정 상황에서 최상위 문서 frozenness 변경 알고리즘을 true로 실행할 수 있습니다. 예를 들어, 최상위 브라우징 컨텍스트가 백그라운드 또는 숨김 상태이고 유예 시간이 경과되면 UA는 리소스 절약 및 (포그라운드) 사용자 경험 품질 유지를 위해 최상위 문서 frozenness 변경을 true로 실행할 수 있습니다. 구체적 예시:

UA는 사용자가 해당 브라우징 컨텍스트를 다시 방문할 때 최상위 문서 frozenness 변경 알고리즘을 false로 실행합니다. 또한, 리소스가 충분할 경우 백그라운드에서도 주기적으로 최상위 문서 frozenness 변경을 false로 실행할 수 있습니다.

5.4.2. 문서 frozenness 변경

최상위 문서 frozenness 변경을 실행하려면, Document topLevelDoc과 불리언 frozenness 상태 frozenness가 주어졌을 때:
  1. Assert: doc브라우징 컨텍스트최상위 브라우징 컨텍스트임을 확인합니다.

  2. 문서 frozenness 변경topLevelDoc, frozenness, false로 실행합니다.

  3. descendants하위 브라우징 컨텍스트 리스트로 설정합니다.

  4. 브라우징 컨텍스트 bdescendants에서 반복:

    1. descendantDocumentactive document로 설정합니다.

    2. 문서 frozenness 변경descendantDocument, frozenness, false로 실행합니다.

문서 frozenness 변경을 실행하려면, Document doc, 불리언 frozenness 상태 frozenness, 불리언 auto resume frozen media가 주어졌을 때:
  1. frozenness가 true이면, freeze stepsdoc, auto resume frozen media와 함께 실행합니다.

  2. 그렇지 않으면, resume stepsdoc에 대해 실행합니다.

freeze steps를 실행하려면, Document doc과 불리언 auto resume frozen media가 주어졌을 때:
  1. docfrozenness 상태를 true로 설정합니다.

  2. freeze 이벤트를 doc에 발생시킵니다.

  3. elements미디어 요소docshadow-including descendants (shadow-including tree order)로 설정합니다.

  4. elements의 각 element에 대해:

    1. elementpaused가 false이면:

      1. elementresume frozen flagauto resume frozen media로 설정합니다.

      2. media pauseelement에 실행합니다.

    참고: frozenness 상태 값을 먼저 할당하고 이벤트를 발생시키는 순서가 의도적입니다.

resume steps를 실행하려면, Document doc이 주어졌을 때:
  1. elements미디어 요소docshadow-including descendants (shadow-including tree order)로 설정합니다.

    1. elements의 각 element에 대해:

      1. elementsresume frozen flag가 true이면:

        1. elementsresume frozen flag를 false로 설정합니다.

        2. media playelement에 실행합니다.

  2. resume 이벤트를 doc에 발생시킵니다.

  3. docfrozenness 상태를 false로 설정합니다.

    참고: frozenness 상태 값 할당이 이벤트 발생 이후 마지막에 수행되는 것이 의도적입니다.

5.4.3. Discarding

각 Document는 discarded 불리언을 가지며, 초기값은 false입니다.

discard를 실행하려면 브라우징 컨텍스트를 destroy하고, 그것과 하위 브라우징 컨텍스트들이 discard된 이유가 discard 때문임을 기록합니다.

참고: Discard는 일반적으로 시스템 메모리 회수(메모리 등 리소스 부족 시)에 사용됩니다. 반면 브라우저 컨텍스트 destroy는 사용자가 페이지를 떠나는 등의 일반적인 해제 과정입니다.

브라우징 컨텍스트가 백그라운드에 있고, 그 문서가 VisibilityState hidden 상태라면, 리소스 압박(예: 메모리 부족) 시 discarded될 수 있습니다. 구체적 예시:

최상위 브라우징 컨텍스트(브라우저의 탭)가 리소스 압박(또는 예기치 않은 이벤트, 예: 프로세스 크래시)으로 인해 discarded된 후 사용자가 브라우저에서 해당 탭을 다시 방문하면, Documentdiscarded 불리언이 § 5.2.5 문서 초기화에 따라 true가 됩니다.

6. 감사의 글

다음 분들께 특별히 감사드립니다. Dave Tapuska, Fadi Meawad, Ojan Vafai, Olli Pettay, Philip Walton, 그리고 Todd Reifsteck. 이 명세에 대한 기술적 의견과 제안으로 개선에 큰 도움을 주셨습니다.

정합성

문서 관례

정합성 요구사항은 설명적 단언과 RFC 2119 용어의 조합으로 표현됩니다. 명세의 규범적 부분에서 “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, “OPTIONAL”이라는 주요 단어들은 RFC 2119에서 설명된 대로 해석되어야 합니다. 다만, 가독성을 위해 이 단어들은 모두 대문자로 표기되지 않습니다.

이 명세서의 모든 텍스트는 명시적으로 비규범적, 예시, 참고로 표시된 부분을 제외하면 규범적입니다. [RFC2119]

이 명세서의 예시는 “for example”라는 문구로 도입하거나, class="example"로 규범적 텍스트와 구분해 아래처럼 제시됩니다:

이것은 정보성 예시의 예입니다.

정보성 참고는 “Note”라는 단어로 시작하며, class="note"로 규범적 텍스트와 구분해 아래처럼 표시됩니다:

참고, 이것은 정보성 참고입니다.

정합성 알고리즘

알고리즘에서 명령문 형태로 작성된 요구사항(예: "strip any leading space characters" 또는 "return false and abort these steps")은 키워드("must", "should", "may" 등)가 알고리즘 소개에 사용된 의미로 해석해야 합니다.

알고리즘이나 특정 단계로 표현된 정합성 요구사항은 결과가 동일하다면 어떤 방식으로든 구현할 수 있습니다. 특히, 이 명세서에서 정의하는 알고리즘은 이해하기 쉽게 작성된 것이며, 성능을 위한 것이 아닙니다. 구현자는 최적화를 권장합니다.

색인

이 명세서에서 정의된 용어

참조로 정의된 용어

참고 문헌

규범 참고 문헌

[CSS21]
Bert Bos; et al. Cascading Style Sheets Level 2 Revision 1 (CSS 2.1) Specification. URL: https://drafts.csswg.org/css2/
[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/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra Standard. Living Standard. URL: https://infra.spec.whatwg.org/
[PERMISSIONS-POLICY-1]
Ian Clelland. Permissions Policy. URL: https://w3c.github.io/webappsec-permissions-policy/
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. March 1997. Best Current Practice. URL: https://datatracker.ietf.org/doc/html/rfc2119
[SERVICE-WORKERS-1]
Alex Russell; et al. Service Workers 1. URL: https://w3c.github.io/ServiceWorker/
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL Standard. Living Standard. URL: https://webidl.spec.whatwg.org/

정보 참고 문헌

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

IDL 색인

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

partial interface Client {
    readonly attribute ClientLifecycleState lifecycleState;
};

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