1. 소개
많은 웹 앱(및 탭)이 실행 중일 때, 메모리, CPU, 배터리, 네트워크 등과 같은 중요한 리소스가 쉽게 과부하되어 최종 사용자 경험이 나빠집니다. 애플리케이션 라이프사이클은 현대 OS가 리소스를 관리하는 핵심 방법입니다.플랫폼이 애플리케이션 라이프사이클을 지원하려면, 다음을 제공해야 합니다:
-
라이프사이클 상태 전환에 대한 신호를 개발자에게 제공
-
앱이 백그라운드로 이동하거나 정지되더라도 핵심 기능이 동작할 수 있도록 라이프사이클 호환 API를 제공
이 제안서는 웹 페이지의 라이프사이클이 무엇인지 정의하고, 사용자 에이전트가 흔히 수행하는 두 가지 주요 라이프사이클 이벤트에 웹 애플리케이션이 대응할 수 있도록 필요한 확장을 추가합니다:
-
탭 디스카드(메모리 절약용)
-
CPU 중지(배터리, 데이터, CPU 절약용)
2. 페이지 라이프사이클 상태
이 명세는 웹 페이지의 라이프사이클이 무엇인지 정의하고, 사용자 에이전트가 흔히 수행하는 두 가지 주요 라이프사이클 이벤트에 웹 애플리케이션이 대응할 수 있도록 확장을 추가합니다:
-
CPU 중지(배터리, 데이터, CPU 절약용)
-
탭 디스카드(메모리 절약용)
이 명세는 위 기능을 지원하기 위해 두 가지 새로운 라이프사이클 상태를 공식화합니다:
-
Frozen: CPU 중지를 위한 라이프사이클 상태. 이는 freeze steps 알고리즘이
Document
의 브라우징 컨텍스트에서 호출된 경우입니다. 일반적으로 HIDDEN 페이지는 리소스 절약을 위해 frozen 상태가 됩니다. -
Discarded: discard 알고리즘이
Document
의 브라우징 컨텍스트에서 호출된 경우입니다. 일반적으로 frozen 프레임은 리소스 절약을 위해 discarded 상태로 이동합니다.
TODO(panicker): 다이어그램 삽입
3. API
페이지 라이프사이클은 다음과 같은 추가 기능을 포함합니다:
partial interface Document {attribute EventHandler onfreeze ;attribute EventHandler onresume ;readonly attribute boolean wasDiscarded ; };
onfreeze
및 onresume
속성은 각각 freeze
및 resume
이벤트에 대한 이벤트 핸들러 IDL 속성입니다.
wasDiscarded
속성의 getter는 해당 Document
의
discarded 불리언 값을 반환해야
합니다.
참고: 이 API들은 Document
에
추가되며,
Window
가
아닌 이유는 Page Visibility API와의 일관성을 위해서입니다. 이 API들은 기존 Page Visibility API와 함께 사용될 것으로 기대합니다. [PAGE-VISIBILITY]
참고: 추가로 clientId
및
discardedClientId
가 Window
에
추가되어, 사용자가 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 상태로 둡니다:
-
iframe load 이벤트 단계가 실행됨;
-
해당 문서에 대해 정책이 비활성화됨;
-
정책 조건이 적용됨(렌더링 중이 아니거나, 뷰포트에서 스크롤 아웃됨)
이 조건이 만족되지 않으면 문서는 unfrozen 상태가 됩니다.
<!-- iframe은 로드 직후 frozen 상태가 됩니다. --> < iframe allow = "execution-while-not-rendered 'none'" src = "subframe.html" style = "display:none" ></ iframe >
Document
document에 대해 문서 frozenness 갱신 단계를 실행하려면:
-
document의 브라우징 컨텍스트가 중첩 브라우징 컨텍스트가 아니면 return.
-
document의 readiness가 "
complete
"가 아니면 return. -
element를 document의 브라우징 컨텍스트의 브라우징 컨텍스트 컨테이너로 설정.
-
frozenness를 false로 설정.
-
auto resume media를 false로 설정.
-
document가 "execution-while-not-rendered" 기능을 사용할 수 없으면:
-
element가 렌더링 중이 아니면 frozenness를 true로 설정.
-
-
그 외에 document가 "execution-while-out-of-viewport" 기능을 사용할 수 없으면:
-
frozenness가 document의 frozenness 상태와 다르면, 문서 frozenness 변경을 document, frozenness, auto resume media로 실행.
5. 처리 모델
5.1. 워크렛 및 워커 동작 수정
단일 realm의 worklet agent의 global object의 owning document가 frozen이면 blocked가 되어야 합니다. 단일 dedicated worker agent의 realm의 global object의 owning document가 null이 아니고 frozen이면 blocked가 되어야 합니다.
DedicatedWorkerGlobalScope
workerGlobalScope의 owning document 결정
방법:
-
workerGlobalScope의 owner set에 단일
Document
document만 있으면 document 반환. -
workerGlobalScope의 owner set에 단일
DedicatedWorkerGlobalScope
parentWorkerGlobalScope만 있으면 parentWorkerGlobalScope의 owning document 반환. -
null 반환.
참고: DedicatedWorkerGlobalScope
의
owner set은 항상 정확히 1개의 항목만 가집니다.
5.2. HTML 표준 수정
5.2.1. 문서 언로딩 및 히스토리 트래버설
문서가 bfcache(back forward cache)로 이동하거나 복귀할 때 각각 frozenness 상태를 true, false로 전환합니다.
-
문서 언로딩 알고리즘에서 Step #5 이후,
persisted
속성이 true(즉, bfcache로 이동)라면 문서 frozenness 변경을 document, true로 실행. -
히스토리 트래버설 알고리즘에서 Step #4.6.4 이전,
persisted
속성이 true(즉, bfcache에서 복귀)라면 문서 frozenness 변경을 document, false로 실행.
5.2.2. 이벤트 루프: 정의
교체: task는 해당 document가 null이거나 fully active일 때 실행 가능하다.
변경 후: task는 해당 document가 null이거나 fully active이고, 또한 unfrozen 상태여야 실행 가능하다.
5.2.3. 이벤트 루프: 처리 모델
렌더링 업데이트 중 Step #11 이후에 다음 단계를 추가한다.
각 fully active Document
doc가 docs에 있을 때, update document frozenness steps를 doc에 대해
실행한다.
5.2.4. 브라우징 컨텍스트 디스카드
브라우징 컨텍스트와 문서 모두에 대해 "discard"
개념의 이름을 "destroy"로 변경한다. 이렇게 하면 사용자에게 표시되는 wasDiscarded
속성에 "discarded" 용어를 사용할 수 있다.
5.2.5. 문서 초기화
Step #3 이전에 다음을 추가한다:
브라우징 컨텍스트가 이전에 discarded 상태였으면, 해당
Document
의
discarded 불리언을 true로
설정한다.
5.2.6. iframe load 이벤트 단계
Step #5 이후에 다음을 추가한다:
child document에 대해 update document frozenness steps를 실행한다.
5.2.7. HTMLMediaElement
각 HTMLMediaElement
는 resume frozen flag를 가지며, 초기값은 false이다.
5.2.8. 메시지 전송
다음 참고를 추가한다:
참고: frozen 상태의 Window
로
메시지를 전송할 때, posted message task source에 대기 중인 이벤트들은 Window
가
unfrozen 상태가 될 때까지 실행되지 않는다. 이벤트 대기열이 너무
많아지면, 사용자 에이전트는 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에서 변수명을 변경합니다.
-
matchedClientData를 새로운 리스트로 설정합니다.
Step #2.5.1 이전에 다음을 삽입합니다.
-
lifecycleState를 Get Client Lifecycle State를 client와 함께 실행한 결과로 설정합니다.
Step #5.3.1에서 리스트에 lifecycleState를 추가합니다.
-
windowData를 «[ "client" → client, "ancestorOriginsList" → 새로운 리스트, "lifecycleState" → lifecycleState ]»로 설정합니다.
Step #5.4에서 matchedClientData에 lifecycleState를 추가합니다.
-
«[ "client" → client, "lifecycleState" → lifecycleState ]»를 matchedClientData에 추가합니다.
Step #6.2에서 windowData의 lifecycleState를 Create Window Client 알고리즘에 전달합니다.
-
windowClient를 Create Window Client 알고리즘을 windowData["
client
"], windowData["frameType
"], windowData["visibilityState
"], windowData["focusState
"], windowData["ancestorOriginsList
"], windowData["lifecycleState
"]를 인자로 하여 실행한 결과로 설정합니다.
Step #6.3을 조정합니다.
-
각 clientData를 matchedClientData에서 반복:
-
clientObject를 Create Client 알고리즘을 clientData["
client
"], clientData["lifecycleState
"]로 실행한 결과로 설정합니다. -
clientObject를 clientObjects에 추가합니다.
-
5.3.1.3.
openWindow(url)
Step #7.5 이전에 다음을 삽입합니다.
-
lifecycleState를 Get Client Lifecycle State를 this의 연결된 service worker client와 함께 실행한 결과로 설정합니다.
Step #7.8.2에서 lifecycleState를 제공하도록 조정합니다.
-
client를 Create Window Client를 newContext의
Window
객체의 environment settings object, frameType, visibilityState, focusState, ancestorOriginsList, lifecycleState를 인자로 하여 실행한 결과로 설정합니다.
5.3.2. 알고리즘
5.3.2.1. 클라이언트 라이프사이클 상태 가져오기
다음 알고리즘을 추가합니다:
- 입력
-
client, service worker client
- 출력
-
state, 문자열
-
state를
"active"
로 설정합니다. -
client의 global object의 owning document가 frozen이면 state를
"frozen"
으로 설정합니다. -
state를 반환합니다.
5.3.2.2. 클라이언트 생성
입력에 lifecycleState (문자열)을 추가합니다.
출력의 Step #2 이후에 다음을 추가합니다.
-
clientObject의 라이프사이클 상태를 lifecycleState로 설정합니다.
5.3.2.3. Window 클라이언트 생성
입력에 lifecycleState (문자열)을 추가합니다.
출력의 Step #5 이후에 다음을 추가합니다.
-
windowClient의 라이프사이클 상태를 lifecycleState로 설정합니다.
5.4. 페이지 라이프사이클 처리 모델
5.4.1. FROZENNESS 상태
Document는 아래 FROZENNESS 상태 중 하나일 수 있습니다:-
true: 문서가 frozen 상태이며, 그 문서와 관련된 태스크는 실행되지 않습니다.
-
false: 문서가 unfrozen 상태이며, 그 문서와 관련된 태스크는 평소처럼 실행됩니다.
참고: 최상위 문서 frozenness 변경 알고리즘에 따라, 최상위 브라우징 컨텍스트의 Document가 frozenness 상태를 변경하면 모든 하위 브라우징 컨텍스트의 문서들도 동일한 값으로 frozenness가 변경되어(최상위 브라우징 컨텍스트의 Document와 일치) 일관성을 유지합니다.
UA는 특정 상황에서 최상위 문서 frozenness 변경 알고리즘을 true로 실행할 수 있습니다. 예를 들어, 최상위 브라우징 컨텍스트가 백그라운드 또는 숨김 상태이고 유예 시간이 경과되면 UA는 리소스 절약 및 (포그라운드) 사용자 경험 품질 유지를 위해 최상위 문서 frozenness 변경을 true로 실행할 수 있습니다. 구체적 예시:
-
모바일 Chrome에서는, 백그라운드로 5분 이상 있었던 탭이 frozen이 될 수 있으며, 배터리와 데이터를 절약합니다.
-
데스크톱 Chrome에서는, 사용자에게 중요하지 않은(오랜 시간 사용되지 않은) 백그라운드 탭이 discarded 상태가 될 수 있으며, 메모리를 절약합니다.
참고: 사용자를 위해 실제로 작업 중인(예: 오디오 재생 중인) 백그라운드 탭은 일반적으로 frozen이나 discarded 상태가 되지 않습니다.
참고: Chrome에서 사용되는 휴리스틱 및 예외에 대한 상세 목록은 이 문서를 참고하세요.
UA는 사용자가 해당 브라우징 컨텍스트를 다시 방문할 때 최상위 문서 frozenness 변경 알고리즘을 false로 실행합니다. 또한, 리소스가 충분할 경우 백그라운드에서도 주기적으로 최상위 문서 frozenness 변경을 false로 실행할 수 있습니다.
5.4.2. 문서 frozenness 변경
Document
topLevelDoc과 불리언 frozenness 상태 frozenness가 주어졌을 때:
-
Assert: doc의 브라우징 컨텍스트는 최상위 브라우징 컨텍스트임을 확인합니다.
-
문서 frozenness 변경을 topLevelDoc, frozenness, false로 실행합니다.
-
descendants를 하위 브라우징 컨텍스트 리스트로 설정합니다.
-
각 브라우징 컨텍스트 b를 descendants에서 반복:
-
descendantDocument를 active document로 설정합니다.
-
문서 frozenness 변경을 descendantDocument, frozenness, false로 실행합니다.
-
Document
doc, 불리언 frozenness 상태 frozenness, 불리언 auto resume frozen
media가 주어졌을 때:
-
frozenness가 true이면, freeze steps를 doc, auto resume frozen media와 함께 실행합니다.
-
그렇지 않으면, resume steps를 doc에 대해 실행합니다.
Document
doc과 불리언 auto resume frozen media가 주어졌을 때:
-
doc의 frozenness 상태를 true로 설정합니다.
-
freeze 이벤트를 doc에 발생시킵니다.
-
elements를 미디어 요소 중 doc의 shadow-including descendants (shadow-including tree order)로 설정합니다.
-
elements의 각 element에 대해:
-
element의
paused
가 false이면:-
element의 resume frozen flag를 auto resume frozen media로 설정합니다.
-
media pause를 element에 실행합니다.
-
참고: frozenness 상태 값을 먼저 할당하고 이벤트를 발생시키는 순서가 의도적입니다.
-
Document
doc이 주어졌을 때:
-
elements를 미디어 요소 중 doc의 shadow-including descendants (shadow-including tree order)로 설정합니다.
-
elements의 각 element에 대해:
-
elements의 resume frozen flag가 true이면:
-
elements의 resume frozen flag를 false로 설정합니다.
-
media play를 element에 실행합니다.
-
-
-
-
resume 이벤트를 doc에 발생시킵니다.
-
doc의 frozenness 상태를 false로 설정합니다.
참고: frozenness 상태 값 할당이 이벤트 발생 이후 마지막에 수행되는 것이 의도적입니다.
5.4.3. Discarding
각 Document는 discarded 불리언을 가지며, 초기값은 false입니다.discard를 실행하려면 브라우징 컨텍스트를 destroy하고, 그것과 하위 브라우징 컨텍스트들이 discard된 이유가 discard 때문임을 기록합니다.
참고: Discard는 일반적으로 시스템 메모리 회수(메모리 등 리소스 부족 시)에 사용됩니다. 반면 브라우저 컨텍스트 destroy는 사용자가 페이지를 떠나는 등의 일반적인 해제 과정입니다.
브라우징 컨텍스트가 백그라운드에 있고, 그 문서가 VisibilityState hidden 상태라면, 리소스 압박(예: 메모리 부족) 시 discarded될 수 있습니다. 구체적 예시:
-
데스크톱 Chrome에서는, 사용자에게 중요하지 않은(오랜 시간 사용되지 않은) 백그라운드 탭이 discarded 상태가 될 수 있으며, 메모리를 절약합니다.
참고: 사용자를 위해 실제로 작업 중인(예: 오디오 재생 중인) 백그라운드 탭은 일반적으로 discarded 상태가 되지 않습니다.
참고: Chrome에서 사용되는 휴리스틱 및 예외에 대한 상세 목록은 이 문서를 참고하세요.
최상위 브라우징 컨텍스트(브라우저의 탭)가 리소스 압박(또는 예기치 않은 이벤트, 예: 프로세스
크래시)으로 인해 discarded된 후 사용자가 브라우저에서 해당
탭을 다시 방문하면, Document
의
discarded 불리언이 § 5.2.5 문서 초기화에 따라 true가 됩니다.
6. 감사의 글
다음 분들께 특별히 감사드립니다. Dave Tapuska, Fadi Meawad, Ojan Vafai, Olli Pettay, Philip Walton, 그리고 Todd Reifsteck. 이 명세에 대한 기술적 의견과 제안으로 개선에 큰 도움을 주셨습니다.