서비스 워커 나이트리

W3C 후보 권고안 초안,

이 문서에 대한 추가 정보
이 버전:
https://www.w3.org/TR/2026/CRD-service-workers-20260917/
최신 공개 버전:
https://www.w3.org/TR/service-workers/
에디터스 드래프트:
https://w3c.github.io/ServiceWorker/
이전 버전:
히스토리:
https://www.w3.org/standards/history/service-workers/
구현 보고서:
https://wpt.fyi/results/service-workers
테스트 슈트:
https://github.com/web-platform-tests/wpt/tree/master/service-workers
피드백:
GitHub
명세 내 인라인
에디터:
(Microsoft)
(Google)
이전 에디터:
(Google)
(Google)
(Microsoft, 2018년 4월까지 삼성 대리)
(Google)

요약

이 명세의 핵심은 이벤트를 수신하기 위해 깨어나는 워커입니다. 이는 다른 목적지가 적합하지 않거나, 다른 목적지가 존재하지 않을 때 사용할 수 있는 이벤트 목적지를 제공합니다.

예를 들어, 개발자가 페이지를 어떻게 가져올지 결정할 수 있도록 하려면, 해당 출처에 대한 다른 실행 컨텍스트가 존재하기 전에 이벤트가 디스패치되어야 할 수 있습니다. 푸시 메시지에 반응하거나, 지속적인 다운로드가 완료될 때, 원래 관심을 등록한 컨텍스트가 더 이상 존재하지 않을 수도 있습니다. 이런 경우에 서비스 워커가 이상적인 이벤트 목적지가 됩니다.

이 명세는 또한 fetch 이벤트와 HTTP 캐시와 유사한 설계의 요청 및 응답 저장소를 제공하여 오프라인 사용이 가능한 웹 애플리케이션을 더 쉽게 구축할 수 있도록 합니다.

이 문서의 상태

이 섹션은 본 문서가 공개된 시점의 상태를 설명합니다. 현재 W3C의 모든 발행 문서와 본 기술 보고서의 최신 개정판 목록은 W3C 표준 및 초안 색인에서 확인할 수 있습니다.

본 문서는 웹 애플리케이션 워킹 그룹에 의해 후보 권고안 초안으로 권고안 절차를 통해 발행되었습니다. 후보 권고안으로서의 발행은 W3C 및 그 회원의 공식적인 승인이나 지지를 의미하지 않습니다. 후보 권고안 초안에는 워킹 그룹이 다음 후보 권고안 스냅샷에 포함하고자 하는 이전 후보 권고안의 변경 사항이 반영됩니다.

본 문서는 초안이며, 언제든지 업데이트, 대체, 또는 다른 문서에 의해 폐기될 수 있습니다. 진행 중인 작업 외의 근거로 이 문서를 인용하는 것은 적절하지 않습니다.

본 문서는 라이브 문서입니다. 독자들은 이 명세에 구현되지 않은 기능이나 세부 사항이 포함되어 있을 수 있고, 내용이 변경될 수 있음을 인지해야 합니다. Service Workers 1은 W3C 권고로 진행 중인 버전입니다.

이 문서는 W3C 특허 정책에 따라 운영되는 그룹에서 작성되었습니다. W3C는 그룹 산출물과 관련된 공개 특허 공개 목록을 관리하고 있습니다. 해당 페이지에는 특허 공개 방법에 대한 안내도 포함되어 있습니다. 실제로 특허의 필수 청구항을 포함한다고 판단되는 특허 지식을 보유한 개인은 W3C 특허 정책 6항에 따라 해당 사항을 공개해야 합니다.

이 문서는 2025년 8월 18일 W3C 프로세스 문서에 의해 관리됩니다.

1. 동기

이 섹션은 비규범적입니다.

웹 애플리케이션은 전통적으로 네트워크에 접근할 수 있다는 가정을 합니다. 이 가정은 플랫폼 전반에 퍼져 있습니다. HTML 문서는 HTTP를 통해 로드되고, 전통적으로 모든 하위 리소스를 이후의 HTTP 요청을 통해 가져옵니다. 이는 웹 콘텐츠가 다른 기술 스택에 비해 불리하게 만듭니다.

서비스 워커는 내비게이션이 발생하려고 할 때 런타임이 시작할 수 있는 웹 워커 컨텍스트를 제공함으로써 이러한 불균형을 해소하기 위해 설계되었습니다. 이 이벤트 기반 워커는 출처와 경로(또는 패턴)에 대해 등록되므로, 해당 위치로 내비게이션이 발생할 때 참조될 수 있습니다. 네트워크 요청에 해당하는 이벤트가 워커로 전달되고, 워커가 생성한 응답은 기본 네트워크 스택 동작을 대체할 수 있습니다. 서비스 워커는 개념적으로 네트워크와 문서 렌더러 사이에 위치하므로, 서비스 워커가 오프라인 상태에서도 문서에 콘텐츠를 제공할 수 있게 합니다.

오프라인 문제를 해결하기 위한 이전의 시도에 익숙한 웹 개발자들은 그러한 솔루션의 유연성이 부족하다고 보고했습니다. 그 결과 서비스 워커는 개발자에게 추가적인 복잡성을 요구하는 대신 최대한의 유연성을 제공하기 위해 매우 절차적으로 설계되었습니다. 이러한 복잡성의 일부는 서비스 워커가 단일 스레드 실행 모델에서도 응답성을 유지해야 한다는 필요성에서 비롯됩니다. 그 결과, 서비스 워커에서 노출되는 API는 거의 전부 비동기적으로 설계되어, 다른 자바스크립트 환경에서 익숙한 패턴이지만 문서와 리소스 로딩의 블로킹을 피해야 한다는 점에서 더욱 강조되었습니다.

HTML5 애플리케이션 캐시를 사용하는 개발자들은 설계의 여러 속성이 복구 불가능한 오류를 유발한다고 보고한 바 있습니다. 서비스 워커의 핵심 설계 원칙 중 하나는 오류가 항상 복구 가능해야 한다는 점입니다. 서비스 워커의 업데이트 과정의 많은 세부사항은 이러한 위험을 피하도록 설계되었습니다.

서비스 워커는 문서가 아니라 이벤트와의 관계를 통해 시작되고 유지됩니다. 이러한 설계는 개발자와 벤더가 공유 워커 및 Chrome 배경 페이지에서 얻은 경험에서 크게 차용한 것입니다. 이러한 시스템에서 얻은 주요 교훈 중 하나는 리소스를 절약하고, 백그라운드 컨텍스트가 손실되거나 다시 시작될 수 있음을 개발자가 항상 염두에 두도록 백그라운드 처리 컨텍스트의 실행 시간을 제한해야 한다는 점입니다. 그 결과, 서비스 워커는 Chrome 배경 페이지의 후속 버전인 Chrome 이벤트 페이지와 매우 유사한 특성을 갖습니다. 서비스 워커는 사용자 에이전트에 의해 문서가 연결되지 않은 상태에서 시작될 수 있으며, 거의 언제라도 사용자 에이전트에 의해 종료될 수 있습니다. 개념적으로, 서비스 워커는 문서에서 메시지를 받지 않고도 시작, 이벤트 처리, 종료가 가능한 공유 워커로 생각할 수 있습니다. 개발자들은 서비스 워커가 초당 여러 번 시작되었다가 종료될 수 있음을 유념해야 합니다.

서비스 워커는 오리진에서 동작하는 범용, 이벤트 기반, 시간 제한이 있는 스크립트 컨텍스트입니다. 이러한 특성 덕분에 서비스 워커는 특정 문서의 컨텍스트 수명을 넘어설 수 있는 다양한 런타임 서비스(예: 푸시 알림 처리, 백그라운드 데이터 동기화, 타 오리진의 리소스 요청에 대한 응답, 고비용 데이터(예: 위치 정보나 자이로스코프)의 중앙 집중식 업데이트 수신 등)의 자연스러운 종단점이 됩니다.

2. 모델

2.1. 서비스 워커

서비스 워커는 웹 워커의 한 종류입니다. 서비스 워커는 등록한 서비스 워커 클라이언트의 출처에서 실행됩니다.

서비스 워커는 "parsed", "installing", "installed", "activating", "activated", "redundant" 중 하나의 상태를 가집니다. 초기 값은 "parsed"입니다.

서비스 워커는 스크립트 url(URL)을 가집니다.

서비스 워커는 "classic" 또는 "module" 중 하나의 타입을 가집니다. 별도 명시가 없는 경우 "classic"입니다.

서비스 워커는 등록된 서비스 워커 레지스트레이션(서비스 워커 레지스트레이션)을 가집니다. 이는 자기 자신을 포함합니다.

서비스 워커는 글로벌 객체(ServiceWorkerGlobalScope 객체 또는 null)을 가집니다.

서비스 워커는 스크립트 리소스(스크립트)를 가집니다. 이는 해당 워커의 스크립트 리소스를 나타냅니다. 초기 값은 null입니다.

스크립트 리소스는 평가된 적 있음 플래그를 가집니다. 초기에는 설정되지 않습니다.

스크립트 리소스는 정책 컨테이너(policy container)를 가집니다. 초기에는 새로운 정책 컨테이너입니다.

서비스 워커는 스크립트 리소스 맵을 가집니다. 이는 순서 있는 맵으로, 키는 URL이고, 값은 응답입니다.

서비스 워커는 사용된 스크립트 집합(집합)을 가집니다. 각 항목은 URL입니다. 초기에는 새로운 집합입니다.

참고: 사용된 스크립트 집합은 설치 후 새 워커의 맵에서 사용하지 않는 리소스를 제거하기 위해 사용됩니다. 이는 업데이트 검사 과정에서 이전 워커의 맵을 기반으로 채워집니다.

서비스 워커는 skip waiting 플래그를 가집니다. 별도 명시가 없는 한 설정되지 않습니다.

서비스 워커는 클래식 스크립트 import됨 플래그를 가집니다. 초기에는 설정되지 않습니다.

서비스 워커는 처리할 이벤트 타입 집합(집합)을 가집니다. 각 항목은 이벤트 리스너의 이벤트 타입입니다. 초기에는 새로운 집합입니다.

서비스 워커는 확장 이벤트 집합(집합)을 가집니다. 각 항목은 ExtendableEvent입니다. 초기에는 새로운 집합입니다.

서비스 워커는 시작 상태를 가집니다. 이는 null 또는 Completion일 수 있으며, 초기에는 null입니다.

서비스 워커는 fetch 리스너가 모두 비어 있음 플래그를 가집니다. 초기에는 설정되지 않습니다.

서비스 워커는 라우터 규칙 목록(리스트의 RouterRule들)입니다. 초기에는 빈 리스트입니다.

서비스 워커는 실행 중이라고 합니다. 이는 이벤트 루프가 실행 중일 때를 의미합니다.

서비스 워커는 [[service worker queue]](병렬 큐)를 가집니다.

2.1.1. 수명

서비스 워커의 수명은 이벤트의 실행 수명에 연결되며, 서비스 워커 클라이언트가 ServiceWorker 객체에 보유한 참조와는 관련이 없습니다.

사용자 에이전트는 다음과 같은 상황에서 언제든지 서비스 워커를 종료할 수 있습니다:

  • 처리할 이벤트가 없을 때.

  • 이벤트를 처리하는 중에 무한 루프, 시간 제한 초과 등의 비정상 동작을 감지한 경우.

2.1.2. 이벤트

서비스 워커 명세에서는 서비스 워커 이벤트(각각은 이벤트)를 정의합니다. 여기에는 아래와 같은 것들이 포함됩니다(목록 참조):

2.2. 서비스 워커 타이밍

서비스 워커는 특정 시점을 표시하며, 나중에 navigation timing API와 resource timing API를 통해 노출된다.

서비스 워커 타이밍 정보는 구조체이다. 다음과 같은 항목을 가진다:

시작 시간

DOMHighResTimeStamp, 초기값은 0이다.

fetch 이벤트 디스패치 시간

DOMHighResTimeStamp, 초기값은 0이다.

워커 라우터 평가 시작

DOMHighResTimeStamp, 초기값은 0이다.

워커 캐시 조회 시작

DOMHighResTimeStamp, 초기값은 0이다.

워커 매치된 라우터 소스

DOMString, 초기값은 빈 문자열이다.

워커 최종 라우터 소스

DOMString, 초기값은 빈 문자열이다.

2.3. 서비스 워커 등록

서비스 워커 등록은 범위 URL, 스토리지 키, 서비스 워커 집합, 설치 중인 워커, 대기 중인 워커, 활성 워커의 튜플입니다. 서비스 워커 등록의 범위 URL이 서로 다르다면 사용자 에이전트는 단일 출처에서 여러 서비스 워커 등록을 활성화할 수 있습니다. 동일한 범위 URL의 등록이 사용자 에이전트에 이미 있을 때 서비스 워커 등록을 하면 기존 서비스 워커 등록이 대체됩니다.

서비스 워커 등록은 storage key(storage key)를 가집니다.

서비스 워커 등록은 scope url(URL)을 가집니다.

서비스 워커 등록은 installing worker(서비스 워커 또는 null)로, 상태가 "installing"입니다. 초기값은 null입니다.

서비스 워커 등록은 waiting worker(서비스 워커 또는 null)로, 상태가 "installed"입니다. 초기값은 null입니다.

서비스 워커 등록은 active worker(서비스 워커 또는 null)로, 상태가 "activating" 또는 "activated"입니다. 초기값은 null입니다.

서비스 워커 등록은 마지막 업데이트 검사 시간을 가집니다. 초기값은 null입니다.

서비스 워커 등록은 오래된(stale) 상태가 될 수 있습니다. 이 경우 등록의 마지막 업데이트 검사 시간이 null이 아니고, 현재 시간에서 마지막 업데이트 검사 시간을 뺀 초 단위의 차이가 86400보다 크면 해당됩니다.

서비스 워커 등록은 update via cache mode를 가집니다. 값은 "imports", "all", "none" 중 하나이며, 초기값은 "imports"입니다.

서비스 워커 등록은 하나 이상의 작업 큐(task queue)를 가집니다. 이는 작업을 active worker의 이벤트 루프의 해당 작업 큐에서 백업합니다. (백업의 대상 작업 소스는 handle fetch task source와 handle functional event task source입니다.) 사용자 에이전트는 active worker의 작업을 서비스 워커 등록의 작업 큐에 덤프하며(그 active worker가 종료될 때), 그 active worker가 다시 실행될 때 작업을 다시 큐로 active worker의 이벤트 루프의 해당 작업 큐에 재할당합니다. 작업 큐가 이벤트 루프에 의해 처리되는 것과 달리, 서비스 워커 등록의 작업 큐는 자체적으로 어떤 이벤트 루프에서도 처리되지 않습니다.

서비스 워커 등록은 NavigationPreloadManager 객체를 가집니다.

서비스 워커 등록은 navigation preload enabled 플래그를 가집니다. 초기에는 설정되지 않습니다.

서비스 워커 등록은 navigation preload header 값을 가집니다. 이는 바이트 시퀀스이며, 초기값은 `true`입니다.

서비스 워커 등록은 등록 해제됨(unregistered) 상태가 될 수 있습니다. 이때 registration map[해당 서비스 워커 등록의 (storage key, 직렬화된 scope url)]이 해당 서비스 워커 등록이 아닐 경우입니다.

2.3.1. 수명

사용자 에이전트는 등록된 서비스 워커 등록 목록을 명시적으로 등록 해제하지 않는 한 지속적으로 유지해야 합니다. 사용자 에이전트는 registration map을 가지고 있습니다. 이는 서비스 워커 등록의 (storage key, 직렬화된 scope url) 튜플과 해당 서비스 워커 등록을 저장합니다. 서비스 워커 등록의 수명은 해당 서비스 워커 클라이언트의 수명 내에서 이를 나타내는 ServiceWorkerRegistration 객체의 수명보다 깁니다.

2.4. 서비스 워커 클라이언트

서비스 워커 클라이언트는 environment입니다.

서비스 워커 클라이언트는 discarded flag를 가집니다. 초기에는 설정되지 않습니다.

각 서비스 워커 클라이언트는 다음 environment discarding steps를 따릅니다:

  1. client의 discarded flag를 설정합니다.

참고: discard된 flag가 설정된 클라이언트는 구현에 따라 폐기될 수 있습니다.

서비스 워커 클라이언트는 origin이라는 알고리즘을 가집니다. 이는 서비스 워커 클라이언트가 environment settings object일 경우 서비스 워커 클라이언트의 origin을 반환하고, 그렇지 않으면 서비스 워커 클라이언트의 creation URL의 origin을 반환합니다.

window client는 서비스 워커 클라이언트 중 global object가 Window 객체인 경우입니다.

dedicated worker client는 서비스 워커 클라이언트 중 global object가 DedicatedWorkerGlobalScope 객체인 경우입니다.

shared worker client는 서비스 워커 클라이언트 중 global object가 SharedWorkerGlobalScope 객체인 경우입니다.

worker client는 dedicated worker client 또는 shared worker client입니다.

2.5. 제어 및 사용

서비스 워커 클라이언트는 자신의 로딩과 하위 리소스 처리에 사용되는 active service worker를 가집니다. 서비스 워커 클라이언트가 null이 아닌 active service worker를 가지면, 해당 클라이언트는 그 active service worker에 의해 제어됨(controlled) 상태가 됩니다. 서비스 워커 클라이언트가 서비스 워커에 의해 제어됨 상태일 때, 해당 클라이언트는 서비스 워커의 등록 정보를 사용함(used) 상태라 합니다. 서비스 워커 클라이언트의 active service worker는 아래 하위 섹션에서 설명한 대로 결정됩니다.

이 섹션의 나머지 부분은 비규범적입니다.

이 섹션의 동작은 아직 완전히 명세되지 않았으며, HTML 표준에서 명세될 예정입니다. 관련 작업은 이슈와 풀 리퀘스트에서 추적 중입니다.

2.5.1. 윈도우 클라이언트 케이스

window client는 생성될 때, 즉 browsing context가 생성될 때와 내비게이션이 발생할 때 생성됩니다.

window client가 생성되는 과정에서 browsing context가 생성된다면:

browsing context의 초기 active document의 origin이 opaque origin이면, window client의 active service worker는 null로 설정합니다. 그렇지 않으면, 생성자 document의 서비스 워커 클라이언트의 active service worker로 설정합니다.

window client가 생성되는 과정에서 browsing context의 내비게이션이 발생한다면:

fetch가 HTTP fetch를 통해 라우팅된다면, window client의 active service worker는 서비스 워커 등록 매칭의 결과로 설정합니다. 그렇지 않고 생성된 document의 origin이 opaque origin이거나 생성자 document의 origin과 동일하지 않다면, window client의 active service worker는 null로 설정합니다. 그렇지 않으면, 생성자 document의 서비스 워커 클라이언트의 active service worker로 설정합니다.

참고: 초기 대체 내비게이션의 경우, window client가 생성될 때 browsing context가 생성되지만, active service worker 결정 방식은 위와 동일하게 적용됩니다.

참고: 샌드박스된 iframe 에서 allow-same-origin과 allow-scripts 샌드박싱 지시자가 없으면, 해당 active service worker 값이 null이 됩니다. 이는 origin이 opaque origin이기 때문입니다.

2.5.2. 워커 클라이언트 케이스

worker client는 사용자 에이전트가 워커 환경 설정 객체를 생성할 때, 즉 worker를 실행할 때 생성됩니다.

worker client가 생성될 때:

fetch가 HTTP fetch를 통해 라우팅된다면, worker client의 active service worker는 서비스 워커 등록 매칭의 결과로 설정합니다. 그렇지 않고 worker client의 origin이 opaque origin이거나, request의 URL이 blob URL이고 worker client의 origin이 동일하지 않다면, origin과 owner set의 마지막 worker client의 global object의 owner set과 동일하지 않다면, worker client의 active service worker는 null로 설정합니다. 그렇지 않으면, environment settings object의 마지막 owner set의 worker client의 global object의 owner set의 active service worker로 설정합니다.

참고: Window client와 worker client가 data: URL을 사용하면, 해당 active service worker 값은 null이 되며, 이는 origin이 opaque origin이기 때문입니다. Window client와 worker client가 blob URL을 사용하면, 생성자 document 또는 소유자의 active service worker를 상속받을 수 있습니다. 하지만 request의 origin이 생성자 document 또는 소유자의 origin과 동일하지 않으면, active service worker는 null로 설정됩니다.

2.6. 작업 소스

아래의 추가 작업 소스가 서비스 워커에서 사용됩니다.

fetch 처리 작업 소스

이 작업 소스는 fetch 이벤트를 서비스 워커로 디스패치하는 데 사용됩니다.

기능적 이벤트 처리 작업 소스

이 작업 소스는 기능적 이벤트(예: push 이벤트 등)를 서비스 워커로 디스패치하는 기능에서 사용됩니다.

참고: 사용자 에이전트는 특정 기능적 이벤트의 헤드 오브 라인 블로킹 현상을 방지하기 위해 각 기능적 이벤트 타입마다 별도의 작업 소스를 사용할 수 있습니다.

2.7. 사용자 에이전트 종료

사용자 에이전트는 저장된 서비스 워커 등록의 상태를 재시작 시에도 다음 규칙에 따라 반드시 유지해야 합니다:

이를 위해 사용자 에이전트는 종료 시 Handle User Agent Shutdown을 반드시 호출해야 합니다.

3. 클라이언트 컨텍스트

서비스 워커로 부트스트래핑하기:
// scope는 기본적으로 스크립트가 위치한 경로가 됩니다
// 이 예제에선 "/"
navigator.serviceWorker.register("/serviceworker.js").then(registration => {
  console.log("성공!");
  if (registration.installing) {
    registration.installing.postMessage("설치 중인 페이지에서 인사드립니다.");
  }
}, err => {
  console.error("워커 설치 실패!", err);
});

3.1. ServiceWorker

[SecureContext, Exposed=(Window,Worker)]
interface ServiceWorker : EventTarget {
  readonly attribute USVString scriptURL;
  readonly attribute ServiceWorkerState state;
  undefined postMessage(any message, sequence<object> transfer);
  undefined postMessage(any message, optional StructuredSerializeOptions options = {});

  // event
  attribute EventHandler onstatechange;
};
ServiceWorker includes AbstractWorker;

enum ServiceWorkerState {
  "parsed",
  "installing",
  "installed",
  "activating",
  "activated",
  "redundant"
};

ServiceWorker 객체는 서비스 워커를 나타냅니다. 각 ServiceWorker 객체는 하나의 서비스 워커에 연결되어 있습니다. 여러 문서와 워커에서 ServiceWorker 인터페이스를 구현하는 별개의 객체들이 동시에 같은 서비스 워커에 연관될 수 있습니다.

ServiceWorker 객체는 ServiceWorkerState 객체를 가지고 있으며, 이는 서비스 워커의 상태와 연결되어 있습니다.

3.1.1. ServiceWorker 인스턴스 얻기

environment settings object는 service worker object map을 가집니다. 이는 맵으로, 키는 서비스 워커이고, 값은 ServiceWorker 객체입니다.

service worker 객체 얻기 알고리즘 (serviceWorker: 서비스 워커, environment: environment settings object):
  1. objectMap을 environment의 service worker object map으로 한다.

  2. objectMap[serviceWorker]이 존재하지 않으면 다음을 수행:

    1. serviceWorkerObj를 environment의 Realm에서 생성된 새로운 ServiceWorker 객체로 하고, serviceWorker와 연관시킨다.

    2. serviceWorkerObj의 state 값을 serviceWorker의 state로 설정한다.

    3. objectMap[serviceWorker]에 serviceWorkerObj를 할당한다.

  3. objectMap[serviceWorker]을 반환한다.

3.1.2. scriptURL

scriptURL getter 단계는 서비스 워커의 직렬화된 스크립트 url을 반환한다.

예시: https://example.com/app.html로 내비게이션해서 생성된 문서가 이전에 실행된 다음 등록 호출을 통해 일치하는 등록이 있는 경우:
// 페이지 https://example.com/app.html에 있는 스크립트
navigator.serviceWorker.register("/service_worker.js");

navigator.serviceWorker.controller.scriptURL의 값은 "https://example.com/service_worker.js"가 됩니다.

3.1.3. state

state 속성은 마지막으로 설정된 값을 (ServiceWorkerState 열거형에서) 반환해야 합니다.

3.1.4. postMessage(message, transfer)

postMessage(message, transfer) 메서드 단계:

  1. options를 «[ "transfer" → transfer ]»로 한다.

  2. postMessage(message, options) 를 message와 options로 호출한다.

3.1.5. postMessage(message, options)

postMessage(message, options) 메서드 단계:

  1. serviceWorker를 service worker로, this가 나타내는 서비스 워커로 설정한다.

  2. incumbentSettings를 현재 settings object로 설정한다.

  3. incumbentGlobal를 incumbentSettings의 글로벌 객체로 설정한다.

  4. serializeWithTransferResult를 StructuredSerializeWithTransfer(message, options["transfer"]) 호출 결과로 설정한다. 예외가 발생하면 다시 던진다.

  5. "message"와 serviceWorker를 인자로 Should Skip Event 알고리즘을 실행한 결과가 true라면, return 한다.

  6. 다음 하위 단계들을 병렬로 실행한다:

    1. Run Service Worker 알고리즘을 serviceWorker로 실행한 결과가 failure이면, return 한다.

    2. Queue a task를 DOM manipulation task source 에 생성하여, 다음 단계들을 실행한다:

      1. source를 incumbentGlobal 타입에 따라 결정한다:

        ServiceWorkerGlobalScope
        incumbentGlobal의 service worker를 relevant settings object(즉, serviceWorker의 글로벌 객체에 해당하는 설정 객체)에서 get the service worker object 실행 결과로 선택한다.
        Window
        incumbentGlobal의 relevant settings object를 나타내는 새로운 WindowClient 객체로 선택한다.
        그 외
        incumbentGlobal의 연결된 worker를 나타내는 새로운 Client 객체로 선택한다.
      2. origin을 incumbentSettings의 origin 값으로 설정한다.

      3. destination을 serviceWorker에 연결된 ServiceWorkerGlobalScope 객체로 설정한다.

      4. deserializeRecord를 StructuredDeserializeWithTransfer(serializeWithTransferResult, destination의 Realm) 실행 결과로 설정한다.

        예외가 발생하면, e를 event 생성 결과로 설정한다. 이벤트 이름은 messageerror이고, ExtendableMessageEvent를 사용하며, origin을 origin으로, source 속성을 source로 초기화한다.

      5. 그 외의 경우:

        1. messageClone을 deserializeRecord의 [[Deserialized]] 값으로 설정한다.

        2. newPorts를 frozen array로 생성하며, deserializeRecord의 [[TransferredValues]] 내 모든 MessagePort 객체를 포함, 상대 순서 유지한다.

        3. e를 event 생성 결과로 설정. 이름은 message이고, ExtendableMessageEvent 사용. origin을 origin으로, source를 source로, data를 messageClone으로, ports를 newPorts로 초기화한다.

      6. Dispatch e를 destination에 보낸다.

      7. Update Service Worker Extended Events Set을 serviceWorker와 e를 인자로 호출한다.

3.1.6. 이벤트 핸들러

아래는 이벤트 핸들러(및 해당 이벤트 핸들러 이벤트 타입)로, 이벤트 핸들러 IDL 속성으로 모든 ServiceWorker 인터페이스 객체가 반드시 지원해야 합니다:

이벤트 핸들러 이벤트 핸들러 이벤트 타입
onstatechange statechange

3.2. ServiceWorkerRegistration

[SecureContext, Exposed=(Window,Worker)]
interface ServiceWorkerRegistration : EventTarget {
  readonly attribute ServiceWorker? installing;
  readonly attribute ServiceWorker? waiting;
  readonly attribute ServiceWorker? active;
  [SameObject] readonly attribute NavigationPreloadManager navigationPreload;

  readonly attribute USVString scope;
  readonly attribute ServiceWorkerUpdateViaCache updateViaCache;

  [NewObject] Promise<ServiceWorkerRegistration> update();
  [NewObject] Promise<boolean> unregister();

  // event
  attribute EventHandler onupdatefound;
};

enum ServiceWorkerUpdateViaCache {
  "imports",
  "all",
  "none"
};

ServiceWorkerRegistration 객체는 서비스 워커 등록(서비스 워커 등록)을 가집니다.

3.2.1. ServiceWorkerRegistration 인스턴스 얻기

environment settings object는 서비스 워커 등록 객체 맵을 가집니다. 이는 맵으로, 키는 서비스 워커 등록이고, 값은 ServiceWorkerRegistration 객체입니다.

서비스 워커 등록 객체 얻기 알고리즘 (registration: 서비스 워커 등록, environment: environment settings object):
  1. objectMap을 environment의 서비스 워커 등록 객체 맵으로 한다.

  2. objectMap[registration]이 존재하지 않으면 다음을 수행:

    1. registrationObject를 environment의 Realm에서 생성된 새로운 ServiceWorkerRegistration 객체로 한다.

    2. registrationObject의 서비스 워커 등록을 registration으로 설정한다.

    3. registrationObject의 installing 속성을 null로 설정한다.

    4. registrationObject의 waiting 속성을 null로 설정한다.

    5. registrationObject의 active 속성을 null로 설정한다.

    6. registration의 installing worker가 null이 아니면, registrationObject의 installing 속성을 registration의 installing worker를 environment에서 서비스 워커 객체 얻기로 반환한 값으로 설정한다.

    7. registration의 waiting worker가 null이 아니면, registrationObject의 waiting 속성을 registration의 waiting worker를 environment에서 서비스 워커 객체 얻기로 반환한 값으로 설정한다.

    8. registration의 active worker가 null이 아니면, registrationObject의 active 속성을 registration의 active worker를 environment에서 서비스 워커 객체 얻기로 반환한 값으로 설정한다.

    9. objectMap[registration]에 registrationObject를 할당한다.

  3. objectMap[registration]을 반환한다.

installing 속성은 마지막으로 설정된 값을 반환해야 합니다.

참고: Realm 내에서는, 연관된 서비스 워커마다 하나의 ServiceWorker 객체만 존재합니다.

waiting 속성은 마지막으로 설정된 값을 반환해야 합니다.

참고: Realm 내에서는, 연관된 서비스 워커마다 하나의 ServiceWorker 객체만 존재합니다.

active 속성은 마지막으로 설정된 값을 반환해야 합니다.

참고: Realm 내에서는, 연관된 서비스 워커마다 하나의 ServiceWorker 객체만 존재합니다.

3.2.5. navigationPreload

navigationPreload getter 단계는 서비스 워커 등록의 NavigationPreloadManager 객체를 반환한다.

3.2.6. scope

scope getter 단계는 서비스 워커 등록의 직렬화된 scope url을 반환한다.

§ 3.1.2 scriptURL의 예시에서, registration.scope의 값은 navigator.serviceWorker.ready.then(registration => console.log(registration.scope)) 와 같이 얻을 때 "https://example.com/"이 됩니다.

3.2.7. updateViaCache

updateViaCache getter 단계는 서비스 워커 등록의 update via cache mode를 반환한다.

3.2.8. update()

update() 메서드 단계:

  1. registration을 서비스 워커 등록으로 한다.

  2. newestWorker를 최신 워커 얻기 알고리즘을 registration을 인자로 실행한 결과로 한다.

  3. newestWorker가 null이면, "InvalidStateError" DOMException으로 거부된 프라미스를 반환하고 단계를 중단한다.

  4. this의 관련 글로벌 객체 globalObject가 ServiceWorkerGlobalScope 객체이고, globalObject에 연관된 서비스 워커의 상태가 "installing"이면, "InvalidStateError" DOMException으로 거부된 프라미스를 반환하고 단계를 중단한다.

  5. promise를 프라미스로 한다.

  6. job을 작업 생성 알고리즘을 update, registration의 storage key, registration의 scope url, newestWorker의 script url, promise, this의 관련 settings object를 인자로 실행한 결과로 한다.

  7. job의 worker type을 newestWorker의 type으로 설정한다.

  8. 작업 예약을 job로 호출한다.

  9. promise를 반환한다.

참고: unregister() 메서드는 서비스 워커 등록을 등록 해제합니다. 현재 제어된 서비스 워커 클라이언트의 active service worker의 등록 정보는 해당 서비스 워커 등록을 사용하는 모든 서비스 워커 클라이언트 (자기 자신 포함)가 언로드될 때까지 유효합니다. 즉, unregister() 메서드는 이후의 내비게이션에만 영향을 미칩니다.

unregister() 메서드 단계:

  1. registration을 서비스 워커 등록으로 한다.

  2. promise를 새 프라미스로 한다.

  3. job을 작업 생성 알고리즘을 unregister, registration의 storage key, registration의 scope url, null, promise, this의 관련 settings object를 인자로 실행한 결과로 한다.

  4. 작업 예약을 job로 호출한다.

  5. promise를 반환한다.

3.2.10. 이벤트 핸들러

아래는 이벤트 핸들러(및 해당 이벤트 핸들러 이벤트 타입)로, 이벤트 핸들러 IDL 속성으로 모든 ServiceWorkerRegistration 인터페이스 객체가 반드시 지원해야 합니다:

이벤트 핸들러 이벤트 핸들러 이벤트 타입
onupdatefound updatefound
partial interface Navigator {
  [SecureContext, SameObject] readonly attribute ServiceWorkerContainer serviceWorker;
};

partial interface WorkerNavigator {
  [SecureContext, SameObject] readonly attribute ServiceWorkerContainer serviceWorker;
};

serviceWorker getter 단계는 ServiceWorkerContainer 객체를 반환한다. 해당 객체는 this와 연관되어 있다.

3.4. ServiceWorkerContainer

[SecureContext, Exposed=(Window,Worker)]
interface ServiceWorkerContainer : EventTarget {
  readonly attribute ServiceWorker? controller;
  readonly attribute Promise<ServiceWorkerRegistration> ready;

  [NewObject] Promise<ServiceWorkerRegistration> register((TrustedScriptURL or USVString) scriptURL, optional RegistrationOptions options = {});

  [NewObject] Promise<(ServiceWorkerRegistration or undefined)> getRegistration(optional USVString clientURL = "");
  [NewObject] Promise<FrozenArray<ServiceWorkerRegistration>> getRegistrations();

  undefined startMessages();


  // events
  attribute EventHandler oncontrollerchange;
  attribute EventHandler onmessage; // event.source of message events is ServiceWorker object
  attribute EventHandler onmessageerror;
};
dictionary RegistrationOptions {
  USVString scope;
  WorkerType type = "classic";
  ServiceWorkerUpdateViaCache updateViaCache = "imports";
};

사용자 에이전트는 ServiceWorkerContainer 객체를 Navigator 객체 또는 WorkerNavigator 객체가 생성될 때 만들고 해당 객체와 연관시켜야 한다.

ServiceWorkerContainer 객체는 서비스 워커 등록을 등록, 해제, 업데이트하는 기능을 제공하며, 서비스 워커 등록 및 연관된 서비스 워커의 상태에 접근할 수 있다.

ServiceWorkerContainer 객체는 연관된 서비스 워커 클라이언트를 가진다. 이는 서비스 워커 클라이언트로, global object가 Navigator 객체 또는 WorkerNavigator 객체에서 ServiceWorkerContainer를 가져오며 그 객체와 연관된 것이다.

ServiceWorkerContainer 객체는 연관된 ready promise (promise 또는 null)을 가진다. 초기값은 null이다.

ServiceWorkerContainer 객체는 작업 소스인 클라이언트 메시지 큐를 가진다(초기값은 비어 있음). 클라이언트 메시지 큐는 활성/비활성화 상태가 될 수 있으며, 초기에는 비활성화 상태다. ServiceWorkerContainer 객체의 클라이언트 메시지 큐가 활성화되면, 이벤트 루프는 이를 작업 소스 중 하나로 사용해야 한다. ServiceWorkerContainer 객체의 관련 글로벌 객체가 Window 객체일 때, 클라이언트 메시지 큐에 대기 중인 모든 작업은 해당 settings object의 연관된 문서와 연관되어야 한다.

controller 속성은 다음 단계를 반드시 실행해야 한다:

  1. client를 this의 서비스 워커 클라이언트로 한다.

  2. client의 active service worker 값이 null이면, null을 반환한다.

  3. client의 active service worker를 서비스 워커 객체 얻기로 얻은 값을 this의 settings object에서 반환한다.

참고: navigator.serviceWorker.controller 는 요청이 강제 새로고침(shift+refresh)일 때 null을 반환한다.

ready 속성은 다음 단계를 반드시 실행해야 한다:

  1. this의 ready promise가 null이면, this의 ready promise를 새 프라미스로 설정한다.

  2. readyPromise를 this의 ready promise로 한다.

  3. readyPromise가 pending이면, 다음 하위 단계를 병렬로 실행한다:

    1. client를 this의 서비스 워커 클라이언트로 한다.

    2. storage key를 obtain a storage key를 client에 대해 실행한 결과로 한다.

    3. registration을 서비스 워커 등록 매칭을 storage key와 client의 creation URL을 인자로 실행한 결과로 한다.

    4. registration이 null이 아니고, registration의 active worker가 null이 아니면, 작업 큐에 추가를 readyPromise의 settings object의 responsible event loop에서 DOM manipulation 작업 소스로 실행하여, readyPromise를 서비스 워커 등록 객체 얻기로 registration을 readyPromise의 settings object에서 반환한 값으로 resolve한다.

  4. readyPromise를 반환한다.

참고: 반환된 ready promise는 절대 reject되지 않는다. 만약 이 알고리즘에서 resolve되지 않으면, 매칭되는 서비스 워커 등록이 등록되고 active worker가 설정될 때 결국 resolve된다. (Activate 알고리즘 단계 참고)

참고: register(scriptURL, options) 메서드는 주어진 scope url에 대해 서비스 워커 등록을 생성하거나 업데이트한다. 성공 시, 서비스 워커 등록은 제공된 scriptURL을 scope url에 연결하며, 이후 navigation matching에 사용된다.

register(scriptURL, options) 메서드 단계:

  1. p를 프라미스(promise)로 두자.

  2. scriptURL을 Trusted Type 호환 문자열 얻기를 TrustedScriptURL, this의 관련된 글로벌 오브젝트, scriptURL, "ServiceWorkerContainer register", "script"와 함께 호출한 결과로 설정한다.

  3. client를 this의 service worker 클라이언트로 둔다.

  4. scriptURL을 파싱 scriptURL에 대해 this의 관련 설정 객체의 API 기본 URL과 함께 파싱한 결과로 한다.

  5. scopeURL을 null로 둔다.

  6. 만약 options["scope"] 가 존재한다면, scopeURL을 파싱 options["scope"] 에 대해 this의 관련 설정 객체의 API 기본 URL과 함께 파싱한 결과로 설정한다.

  7. 등록 시작을 scopeURL, scriptURL, p, client, client의 생성 URL, options["type"], 및 options["updateViaCache"] 와 함께 호출한다.

  8. p를 반환한다.

getRegistration(clientURL) 메서드 단계:

  1. client를 this의 서비스 워커 클라이언트로 둔다.

  2. storage key를 client가 주어졌을 때 스토리지 키를 얻는 알고리즘을 실행한 결과로 둔다.

  3. clientURL을 this의 관련 설정 객체의 API 기준 URL을 사용하여 clientURL을 구문 분석한 결과로 둔다.

  4. clientURL이 실패이면, TypeError로 거부된 프로미스를 반환한다.

  5. clientURL의 프래그먼트를 null로 설정한다.

  6. clientURL의 출처가 client의 출처와 같지 않으면, "SecurityError" DOMException으로 거부된 promise를 반환한다.

  7. promise를 새로운 프로미스로 둔다.

  8. 다음 하위 단계를 병렬로 실행한다.

    1. registration을 storage key와 clientURL이 주어졌을 때 서비스 워커 등록 일치시키기를 실행한 결과로 둔다.

    2. promise의 관련 설정 객체의 담당 이벤트 루프에, DOM 조작 태스크 소스를 사용하여 다음 단계를 실행하는 태스크를 큐에 넣는다.

      1. registration이 null이면, promise를 undefined로 이행하고 이 단계를 중단한다.

      2. promise의 관련 설정 객체에서 registration을 나타내는 서비스 워커 등록 객체를 가져온 결과로 promise를 이행한다.

  9. promise를 반환한다.

getRegistrations() 메서드 단계:

  1. client를 this의 서비스 워커 클라이언트로 둔다.

  2. client storage key를 client가 주어졌을 때 스토리지 키를 얻는 알고리즘을 실행한 결과로 둔다.

  3. promise를 새 프로미스로 둔다.

  4. 다음 단계를 병렬로 실행한다.

    1. registrations를 새로운 리스트로 둔다.

    2. 각각에 대해 등록 맵의 (storage key, scope) → registration:

      1. storage key가 client storage key와 같으면, registration을 registrations에 추가한다.

    3. promise의 관련 설정 객체의 담당 이벤트 루프에, DOM 조작 태스크 소스를 사용하여 다음 단계를 실행하는 태스크를 큐에 넣는다.

      1. registrationObjects를 새로운 리스트로 둔다.

      2. registrations의 각 registration에 대해 반복한다.

        1. registrationObj를 promise의 관련 설정 객체에서 registration을 나타내는 서비스 워커 등록 객체를 가져온 결과로 둔다.

        2. registrationObj를 registrationObjects에 추가한다.

      3. promise의 관련 Realm에서 registrationObjects의 새 동결 배열로 promise를 이행한다.

  5. promise를 반환한다.

startMessages() 메서드 단계는 this의 클라이언트 메시지 큐가 비활성화 상태라면 활성화한다.

3.4.7. 이벤트 핸들러

아래는 이벤트 핸들러(및 해당 이벤트 핸들러 이벤트 타입)로, 이벤트 핸들러 IDL 속성으로 모든 ServiceWorkerContainer 인터페이스 객체가 반드시 지원해야 한다:

이벤트 핸들러 이벤트 핸들러 이벤트 타입
oncontrollerchange controllerchange
onmessage message
onmessageerror messageerror

onmessage setter가 처음 수행될 때, this의 클라이언트 메시지 큐를 활성화한다.

3.5. 이벤트

다음 이벤트는 ServiceWorker 객체에서 디스패치됩니다:

이벤트 이름 인터페이스 언제 디스패치되는가…
statechange Event state 속성이 ServiceWorker 객체에서 변경될 때.

다음 이벤트는 ServiceWorkerRegistration 객체에서 디스패치됩니다:

이벤트 이름 인터페이스 언제 디스패치되는가…
updatefound Event 서비스 워커 등록의 installing worker가 변경될 때. (설치 알고리즘의 8단계 참고)

다음 이벤트들은 ServiceWorkerContainer 객체에서 디스패치됩니다:

이벤트 이름 인터페이스 언제 디스패치되는가…
controllerchange Event 서비스 워커 클라이언트의 active service worker 값이 변경될 때. (활성화 알고리즘의 9.2단계 참고. skip waiting 플래그가 설정된 서비스 워커는 서비스 워커 등록 활성화를 서비스 워커 클라이언트가 서비스 워커 등록을 사용 중인 상황에서 발생시킬 수 있으며, navigator.serviceWorker.controller 값은 즉시 active worker를 서비스 워커로 반영하여 제어 중인 서비스 워커 클라이언트임을 나타냅니다.)
message MessageEvent 서비스 워커 클라이언트가 서비스 워커로부터 메시지를 받을 때. postMessage(message, options) 참고.
messageerror MessageEvent 서비스 워커 클라이언트가 서비스 워커로부터 역직렬화할 수 없는 메시지를 받을 때. postMessage(message, options) 참고.
[SecureContext, Exposed=(Window,Worker)]
interface NavigationPreloadManager {
  Promise<undefined> enable();
  Promise<undefined> disable();
  Promise<undefined> setHeaderValue(ByteString value);
  Promise<NavigationPreloadState> getState();
};

dictionary NavigationPreloadState {
  boolean enabled = false;
  ByteString headerValue;
};

enable() 메서드 단계는 다음과 같다:

  1. promise를 새 프로미스로 둔다.

  2. 다음 단계를 병렬로 실행한다:

    1. registration을 this에 연결된 서비스 워커 등록으로 둔다.

    2. registration의 활성 워커가 null이면, 태스크를 큐에 추가한다. promise의 관련 설정 객체의 담당 이벤트 루프에서 DOM 조작 태스크 소스를 사용하여 promise를 "InvalidStateError" DOMException으로 거부하고, 이 단계들을 중단한다.

    3. registration의 내비게이션 프리로드 활성화 플래그를 설정한다.

    4. 태스크를 큐에 추가한다. promise의 관련 설정 객체의 담당 이벤트 루프에서 DOM 조작 태스크 소스를 사용하여 promise를 undefined로 이행한다.

  3. promise를 반환한다.

disable() 메서드 단계는 다음과 같다:

  1. promise를 새 promise로 둔다.

  2. 다음 단계를 병렬로 실행한다:

    1. registration을 this의 연관된 service worker registration으로 둔다.

    2. registration의 active worker가 null이면, task를 큐에 넣어 promise의 relevant settings object의 responsible event loop에서, DOM manipulation task source를 사용해, promise를 reject하고 "InvalidStateError" DOMException으로 처리한 뒤, 이 단계들을 중단한다.

    3. registration의 navigation preload enabled flag를 해제한다.

    4. task를 큐에 넣어 promise의 relevant settings object의 responsible event loop에서, DOM manipulation task source를 사용해, promise를 undefined로 resolve한다.

  3. promise를 반환한다.

setHeaderValue(value) 메서드 단계는 다음과 같다:

  1. value를 정규화한 결과를 value로 둔다.

  2. value가 header value가 아니면, TypeError로 거부된 promise를 반환한다.

  3. promise를 새 promise로 둔다.

  4. 다음 단계를 병렬로 실행한다:

    1. registration을 this의 연관된 service worker registration으로 둔다.

    2. registration의 active worker가 null이면, task를 큐에 넣어 promise의 relevant settings object의 responsible event loop에서, DOM manipulation task source를 사용해, promise를 reject하고 "InvalidStateError" DOMException으로 처리한 뒤, 이 단계들을 중단한다.

    3. registration의 navigation preload header value를 value로 설정한다.

    4. task를 큐에 넣어 promise의 relevant settings object의 responsible event loop에서, DOM manipulation task source를 사용해, promise를 undefined로 resolve한다.

  5. promise를 반환한다.

getState() 메서드 단계는 다음과 같다:

  1. promise를 새 promise로 둔다.

  2. 다음 단계를 병렬로 실행한다:

    1. registration을 this의 연관된 service worker registration으로 둔다.

    2. state를 새로운 NavigationPreloadState 사전으로 둔다.

    3. registration의 navigation preload enabled flag가 설정되어 있으면, state["enabled"]를 true로 설정한다.

    4. state["headerValue"]를 registration의 navigation preload header value로 설정한다.

    5. task를 큐에 넣어 promise의 relevant settings object의 responsible event loop에서, DOM manipulation task source를 사용해 promise를 state로 resolve한다.

  3. promise를 반환한다.

4. 실행 컨텍스트

캐시된 리소스 제공:
// caching.js
self.addEventListener("install", event => {
  event.waitUntil(
    // 리소스 캐시를 연다.
    caches.open("shell-v1").then(cache => {
      // 리소스를 가져오는 과정을 시작한다. 모든 리소스가 저장되어야 성공한다.
      // 하나라도 실패하면 전체 작업이 실패한다.
      return cache.addAll([
        "/app.html",
        "/assets/v1/base.css",
        "/assets/v1/app.js",
        "/assets/v1/logo.png",
        "/assets/v1/intro_video.webm"
      ]);
    })
  );
});

self.addEventListener("fetch", event => {
  // 서비스 워커가 성공적으로 설치되고 활성화되어야만 "fetch" 이벤트가 전달된다.

  // 캐시의 모든 작업은 비동기이므로, URL 매칭도 포함해 promise를 사용한다. e.respondWith()도 promise를 받을 수 있다:
  event.respondWith(
    caches.match(e.request).then(response => {
      return response || fetch(e.request);
    }).catch(() => {
      return caches.match("/fallback.html");
    })
  );
});

4.1. ServiceWorkerGlobalScope

[Global=(Worker,ServiceWorker), Exposed=ServiceWorker, SecureContext]
interface ServiceWorkerGlobalScope : WorkerGlobalScope {
  [SameObject] readonly attribute Clients clients;
  [SameObject] readonly attribute ServiceWorkerRegistration registration;
  [SameObject] readonly attribute ServiceWorker serviceWorker;

  [NewObject] Promise<undefined> skipWaiting();

  attribute EventHandler oninstall;
  attribute EventHandler onactivate;
  attribute EventHandler onfetch;

  attribute EventHandler onmessage;
  attribute EventHandler onmessageerror;
};

ServiceWorkerGlobalScope 객체는 서비스 워커의 글로벌 실행 컨텍스트를 나타낸다.

ServiceWorkerGlobalScope 객체는 서비스 워커(서비스 워커)와 연관된다.

ServiceWorkerGlobalScope 객체는 import 스크립트 캐시 무시 플래그를 가진다. 처음에는 해제되어 있다.

ServiceWorkerGlobalScope 객체는 race response map을 가진다. 이는 순서가 있는 map으로, key는 request이고 value는 race response이다.

race response는 구조체로, "race-network-and-fetch-handler" 실행 시 네트워크 응답을 담는다. value는 response, "pending", 또는 null 이다.

참고: ServiceWorkerGlobalScope 객체는 오리진에서 실행되는 일반적인 이벤트 기반, 시간 제한 스크립트 실행 컨텍스트를 제공한다. 등록에 성공하면 서비스 워커는 이벤트와의 관계에 따라 시작·유지·종료된다. 서비스 워커 클라이언트와는 관련 없다. 서비스 워커 내부에서는 동기 요청을 시작하면 안 된다.

4.1.1. clients

clients getter 단계는 Clients 객체를 this와 연관된 것으로 반환하는 것이다.

4.1.2. registration

registration getter 단계는 서비스 워커 registration 객체를 this의 서비스 워커의 containing service worker registration을 this의 관련 설정 객체에서 반환한다.

4.1.3. serviceWorker

serviceWorker getter 단계는 서비스 워커 객체를 this의 서비스 워커를 this의 관련 설정 객체에서 반환한다.

4.1.4. skipWaiting()

참고: skipWaiting() 메서드는 이 서비스 워커가 registration의 대기 위치에서 활성으로 진행하도록 한다. 서비스 워커 클라이언트가 사용 중이어도 registration이 진행된다.

skipWaiting() 메서드 단계는 다음과 같다:

  1. promise를 새로운 프라미스로 설정한다.

  2. 다음 하위 단계들을 병렬로 실행한다:

    1. 서비스 워커의 skip waiting 플래그를 설정한다.

    2. Try Activate를 서비스 워커의 containing service worker registration에 대해 호출한다.

    3. 태스크를 큐에 넣는다 서비스 워커의 담당 이벤트 루프에서, promise를 undefined로 이행하기 위해 태스크를 큐에 넣는다.

  3. promise를 반환한다.

4.1.5. 이벤트 핸들러

다음은 이벤트 핸들러(그리고 대응되는 이벤트 핸들러 이벤트 타입)로서, 반드시 ServiceWorkerGlobalScope 인터페이스를 구현하는 모든 객체가 이벤트 핸들러 IDL 속성으로 지원해야 한다:

이벤트 핸들러 이벤트 핸들러 이벤트 타입
oninstall install
onactivate activate
onfetch fetch
onmessage message
onmessageerror messageerror

4.2. Client

[Exposed=ServiceWorker]
interface Client {
  readonly attribute USVString url;
  readonly attribute FrameType frameType;
  readonly attribute DOMString id;
  readonly attribute ClientType type;
  undefined postMessage(any message, sequence<object> transfer);
  undefined postMessage(any message, optional StructuredSerializeOptions options = {});
};

[Exposed=ServiceWorker]
interface WindowClient : Client {
  readonly attribute VisibilityState visibilityState;
  readonly attribute boolean focused;
  [SameObject] readonly attribute FrozenArray<USVString> ancestorOrigins;
  [NewObject] Promise<WindowClient> focus();
  [NewObject] Promise<WindowClient?> navigate(USVString url);
};

enum FrameType {
  "auxiliary",
  "top-level",
  "nested",
  "none"
};

Client 객체는 서비스 워커 클라이언트 (a 서비스 워커 클라이언트)와 연관되어 있다.

Client 객체는 프레임 타입과 연관되어 있는데, 이는 "auxiliary", "top-level", "nested", "none" 중 하나이다. 별도의 명시가 없으면 "none"이다.

WindowClient 객체는 브라우징 컨텍스트와 연관되어 있는데, 이는 해당 서비스 워커 클라이언트의 글로벌 객체의 브라우징 컨텍스트이다.

WindowClient 객체에는 visibility state가 연관되어 있으며, 이는 visibilityState 속성값 중 하나입니다.

WindowClient 객체는 포커스 상태와 연관되어 있는데, true 또는 false (초기값은 false)이다.

WindowClient 객체는 조상 출처 배열과 연관되어 있다.

4.2.1. url

url getter 단계는 this가 연관된 서비스 워커 클라이언트의 직렬화된 생성 URL을 반환한다.

4.2.2. frameType

frameType getter 단계는 this의 프레임 타입을 반환한다.

4.2.3. id

id getter 단계는 this가 연관된 서비스 워커 클라이언트의 id를 반환한다.

4.2.4. type

type getter 단계는 다음과 같다:

  1. client를 this의 서비스 워커 클라이언트로 한다.

  2. client가 환경 설정 객체라면:

    1. client가 window client라면 "window"를 반환한다.

    2. 그 외에 client가 dedicated worker client라면 "worker"를 반환한다.

    3. 그 외에 client가 shared worker client라면 "sharedworker"를 반환한다.

  3. 그 외의 경우:

    1. "window" 를 반환한다.

4.2.5. postMessage(message, transfer)

postMessage(message, transfer) 메서드 단계는 다음과 같다:

  1. options를 «[ "transfer" → transfer ]»로 한다.

  2. postMessage(message, options) 를 message와 options를 인수로 하여 호출한다.

4.2.6. postMessage(message, options)

postMessage(message, options) 메서드 단계는 다음과 같다:

  1. contextObject를 this로 둔다.

  2. sourceSettings를 contextObject의 relevant settings object로 둔다.

  3. serializeWithTransferResult를 StructuredSerializeWithTransfer(message, options["transfer"])의 결과로 둔다. 예외가 있으면 그대로 다시 던진다.

  4. 다음 단계를 병렬로 실행한다:

    1. targetClient를 null로 둔다.

    2. 각 service worker client client에 대해:

      1. client가 contextObject의 service worker client이면, targetClient를 client로 설정하고, 중단한다.

    3. targetClient가 null이면, 반환한다.

    4. destination을, 연관된 service worker client가 targetClient인 ServiceWorkerContainer 객체로 둔다.

    5. 다음 단계를 실행하는 task를 destination의 client message queue에 추가한다:

      1. origin을 sourceSettings의 origin으로 둔다.

      2. source를, contextObject의 relevant global object의 service worker를 targetClient에서 나타내는 service worker object를 가져온 결과로 둔다.

      3. deserializeRecord를 StructuredDeserializeWithTransfer(serializeWithTransferResult, destination의 relevant Realm)으로 둔다.

        이 과정에서 예외가 발생하면 이를 포착하고, destination에서 이름이 messageerror인 이벤트를 발생시키며 MessageEvent를 사용한다. 이때 그 origin은 origin으로 초기화하고 source 속성은 source로 초기화한 다음, 이 단계들을 중단한다.

      4. messageClone을 deserializeRecord.[[Deserialized]]로 둔다.

      5. newPorts를, 있다면 deserializeRecord.[[TransferredValues]]에 있는 모든 MessagePort 객체로 구성된 새로운 frozen array로 둔다.

      6. destination에서 이름이 message인 이벤트를 디스패치하며 MessageEvent를 사용한다. 이때 그 origin은 origin으로 초기화하고, source 속성은 source로, data 속성은 messageClone으로, ports 속성은 newPorts로 초기화한다.

4.2.7. visibilityState

visibilityState getter 단계는 this의 가시성 상태를 반환한다.

4.2.8. focused

focused getter 단계는 this의 포커스 상태를 반환한다.

4.2.9. ancestorOrigins

ancestorOrigins getter 단계는 this가 연관된 조상 출처 배열을 반환한다.

4.2.10. focus()

focus() 메서드 단계는 다음과 같다:

  1. 이 origin에 속한 어떤 Window도 transient activation을 갖고 있지 않다면, "InvalidAccessError" DOMException으로 거부된 promise를 반환한다.

  2. serviceWorkerEventLoop를 surrounding agent의 event loop로 둔다.

  3. promise를 새로운 promise로 둔다.

  4. task를 큐에 넣어 this의 연관된 service worker client의 responsible event loop에서, user interaction task source를 사용해 다음 단계를 실행한다:

    1. focusing steps를 this의 browsing context와 함께 실행한다.

    2. frameType을, Get Frame Type을 this의 browsing context와 함께 실행한 결과로 둔다.

    3. visibilityState를 this의 browsing context의 active document의 visibilityState 속성 값으로 둔다.

    4. focusState를 has focus steps를 this의 browsing context의 active document와 함께 실행한 결과로 둔다.

    5. ancestorOriginsList를 this의 browsing context의 active document의 ancestor origins list의 연관된 목록으로 둔다.

    6. task를 큐에 넣어 serviceWorkerEventLoop에서 DOM manipulation task source를 사용해 다음 단계를 실행한다:

      1. windowClient를 Create Window Client를 this의 연관된 service worker client, frameType, visibilityState, focusState, ancestorOriginsList와 함께 실행한 결과로 둔다.

      2. windowClient의 focus state가 true이면, promise를 windowClient로 resolve한다.

      3. 그렇지 않으면, promise를 TypeError로 reject한다.

  5. promise를 반환한다.

4.2.11. navigate(url)

navigate(url) 메서드 단계는 다음과 같다:

  1. url을 파싱한 결과를 url로 두되, 기준은 this의 relevant settings object의 API base URL로 한다.

  2. url이 failure이면, promise를 TypeError로 거부하여 반환한다.

  3. url이 about:blank이면, promise를 TypeError로 거부하여 반환한다.

  4. this의 연관된 service worker client의 active service worker가 this의 relevant global object의 service worker가 아니면, promise를 TypeError로 거부하여 반환한다.

  5. serviceWorkerEventLoop를 current global object의 event loop로 둔다.

  6. promise를 새로운 promise로 둔다.

  7. task를 큐에 넣어 this의 연관된 service worker client의 responsible event loop에서 user interaction task source를 사용하여 다음 단계를 실행한다:

    1. browsingContext를 this의 browsing context로 둔다.

    2. browsingContext의 associated document가 fully active가 아니면, task를 큐에 넣어 serviceWorkerEventLoop에서 DOM manipulation task source를 사용해 promise를 TypeError로 reject하고, 이 단계들을 중단한다.

    3. HandleNavigate: Navigate를 실행하여 browsingContext를 url로 이동시키되, browsingContext의 associated document를 사용하고 exceptionsEnabled를 true로 한다.

    4. HandleNavigate 단계에서 호출된 알고리즘 단계가 예외를 던지면, task를 큐에 넣어 serviceWorkerEventLoop에서 DOM manipulation task source를 사용해 그 예외로 promise를 reject하고, 이 단계들을 중단한다.

    5. frameType을 Get Frame Type을 browsingContext와 함께 실행한 결과로 둔다.

    6. visibilityState를 browsingContext의 active document의 visibilityState 속성 값으로 둔다.

    7. focusState를 has focus steps를 browsingContext의 active document와 함께 실행한 결과로 둔다.

    8. ancestorOriginsList를 browsingContext의 active document의 ancestor origins list의 연관된 목록으로 둔다.

    9. task를 큐에 넣어 serviceWorkerEventLoop에서 DOM manipulation task source를 사용해 다음 단계를 실행한다:

      1. browsingContext의 Window 객체의 environment settings object의 creation URL의 origin이 동일한 것이 service worker의 origin이 아니면, promise를 null로 resolve하고 이 단계들을 중단한다.

      2. windowClient를 Create Window Client를 this의 service worker client, frameType, visibilityState, focusState, ancestorOriginsList와 함께 실행한 결과로 둔다.

      3. promise를 windowClient로 resolve한다.

  8. promise를 반환한다.

4.3. Clients

[Exposed=ServiceWorker]
interface Clients {
  // The objects returned will be new instances every time
  [NewObject] Promise<(Client or undefined)> get(DOMString id);
  [NewObject] Promise<FrozenArray<Client>> matchAll(optional ClientQueryOptions options = {});
  [NewObject] Promise<WindowClient?> openWindow(USVString url);
  [NewObject] Promise<undefined> claim();
};
dictionary ClientQueryOptions {
  boolean includeUncontrolled = false;
  ClientType type = "window";
};
enum ClientType {
  "window",
  "worker",
  "sharedworker",
  "all"
};

사용자 에이전트는 Clients 객체를 ServiceWorkerGlobalScope 객체가 생성될 때 반드시 생성하고 해당 객체에 연관시켜야 한다.

4.3.1. get(id)

get(id) 메서드 단계는 다음과 같다:

  1. promise를 새로운 promise로 둔다.

  2. 다음 하위 단계를 병렬로 실행한다:

    1. service worker client client 각각에 대해, client가 주어졌을 때 storage key를 얻기를 실행한 결과가 연관된 service worker의 containing service worker registration의 storage key와 같은 경우:

      1. client의 id가 id가 아니면, continue한다.

      2. client의 execution ready flag가 설정되거나 client의 discarded flag가 설정될 때까지 기다린다.

      3. client의 execution ready flag가 설정되어 있으면, task를 큐에 넣어 promise의 relevant settings object의 responsible event loop에서, DOM manipulation task source를 사용하여 다음 단계를 실행한다:

        1. Resolve Get Client Promise를 client와 promise로 호출한다.

        2. 이 단계들을 중단한다.

    2. task를 큐에 넣어 promise의 relevant settings object의 responsible event loop에서, DOM manipulation task source를 사용해 promise를 undefined로 resolve한다.

  3. promise를 반환한다.

4.3.2. matchAll(options)

matchAll(options) 메서드 단계는 다음과 같다:

  1. promise를 새 프로미스로 둔다.

  2. 다음 단계를 병렬로 실행한다.

    1. targetClients를 새 목록으로 둔다.

    2. client가 주어졌을 때 스토리지 키를 얻기를 실행한 결과가 연결된 서비스 워커의 포함 서비스 워커 등록의 스토리지 키와 같은 각 서비스 워커 클라이언트 client에 대해:

      1. client의 실행 준비 플래그가 설정되지 않았거나 client의 폐기 플래그가 설정되어 있으면, 계속한다.

      2. client가 보안 컨텍스트가 아니면, 계속한다.

      3. options["includeUncontrolled"]가 false이고, client의 활성 서비스 워커가 연결된 서비스 워커가 아니면, 계속한다.

      4. client를 targetClients에 추가한다.

    3. matchedWindowData를 새 목록으로 둔다.

    4. matchedClients를 새 목록으로 둔다.

    5. targetClients에 있는 각 서비스 워커 클라이언트 client에 대해:

      1. options["type"]이 "window" 또는 "all"이고, client가 환경 설정 객체가 아니거나 윈도 클라이언트이면:

        1. windowData를 «[ "client" → client, "ancestorOriginsList" → 새 목록 ]»으로 둔다.

        2. browsingContext를 null로 둔다.

        3. isClientEnumerable을 true로 둔다.

        4. client가 환경 설정 객체이면, browsingContext를 client의 전역 객체의 브라우징 컨텍스트로 설정한다.

        5. 그렇지 않으면, browsingContext를 client의 대상 브라우징 컨텍스트로 설정한다.

        6. browsingContext의 이벤트 루프에서 사용자 상호작용 태스크 소스를 사용하여 다음 하위 단계를 실행하도록 태스크 task를 큐에 넣는다.

          1. browsingContext가 폐기되었으면, isClientEnumerable을 false로 설정하고 이 단계들을 중단한다.

          2. client가 윈도 클라이언트이고 client의 연결된 문서가 browsingContext의 활성 문서가 아니면, isClientEnumerable을 false로 설정하고 이 단계들을 중단한다.

          3. windowData["frameType"]을 browsingContext로 프레임 유형 가져오기를 실행한 결과로 설정한다.

          4. windowData["visibilityState"]를 browsingContext의 활성 문서의 visibilityState 속성 값으로 설정한다.

          5. windowData["focusState"]를 browsingContext의 활성 문서를 인수로 하여 포커스 여부 단계를 실행한 결과로 설정한다.

          6. client가 윈도 클라이언트이면, windowData["ancestorOriginsList"]를 browsingContext의 활성 문서의 조상 출처 목록에 연결된 목록으로 설정한다.

        7. task의 실행이 완료될 때까지 기다린다.

          참고: 이 대기는 차단 대기이지만, 상태가 손상되지 않는 한 구현자는 반복을 병렬로 실행할 수 있다.

        8. isClientEnumerable이 true이면:

          1. windowData를 matchedWindowData에 추가한다.

      2. 그렇지 않고 options["type"]이 "worker" 또는 "all"이고 client가 전용 워커 클라이언트이거나, options["type"]이 "sharedworker" 또는 "all"이고 client가 공유 워커 클라이언트이면:

        1. client를 matchedClients에 추가한다.

    6. task를 큐에 넣어 다음 단계를 promise의 relevant settings object의 responsible event loop에서 DOM manipulation task source를 사용하여 실행한다:

      1. clientObjects를 새 목록으로 둔다.

      2. matchedWindowData에 있는 각 windowData에 대해 반복한다.

        1. windowClient를 windowData["client"], windowData["frameType"], windowData["visibilityState"], windowData["focusState"] 및 windowData["ancestorOriginsList"]를 인수로 하여 윈도 클라이언트 생성 알고리즘을 실행한 결과로 둔다.

        2. windowClient를 clientObjects에 추가한다.

      3. matchedClients에 있는 각 client에 대해 반복한다.

        1. clientObject를 client를 인수로 하여 클라이언트 생성 알고리즘을 실행한 결과로 둔다.

        2. clientObject를 clientObjects에 추가한다.

      4. clientObjects를 다음과 같이 정렬한다.

        참고: 윈도 클라이언트는 항상 워커 클라이언트보다 먼저 배치된다.

      5. promise의 관련 Realm에서 clientObjects의 새 고정 배열로 promise를 이행한다.

  3. promise를 반환한다.

4.3.3. openWindow(url)

openWindow(url) 메서드 단계는 다음과 같다:

  1. url을 파싱한 결과로 둔다. 이때 this의 관련 설정 객체의 API 기본 URL을 사용하여 url을 파싱한다.

  2. url이 실패이면, TypeError로 거부된 프로미스를 반환한다.

  3. url이 about:blank이면, TypeError로 거부된 프로미스를 반환한다.

  4. 이 출처의 어떠한 Window도 일시적 활성화를 갖고 있지 않으면, "InvalidAccessError" DOMException으로 거부된 프로미스를 반환한다.

  5. serviceWorkerEventLoop를 현재 전역 객체의 이벤트 루프로 둔다.

  6. promise를 새 프로미스로 둔다.

  7. 다음 하위 단계를 병렬로 실행한다:

    1. newContext를 새 최상위 브라우징 컨텍스트로 둔다.

    2. newContext의 Window 객체의 환경 설정 객체의 담당 이벤트 루프에서 사용자 상호작용 태스크 소스를 사용하여 다음 단계를 실행하도록 태스크를 큐에 추가한다:

      1. HandleNavigate: newContext를 url로 내비게이트하며, exceptionsEnabled는 true로 하고, historyHandling은 "replace"로 한다.

      2. HandleNavigate라는 레이블이 지정된 단계에서 호출된 알고리즘 단계가 예외를 던지면, serviceWorkerEventLoop에서 DOM 조작 태스크 소스를 사용하여 promise를 그 예외로 거부하도록 태스크를 큐에 추가하고, 이 단계들을 중단한다.

      3. frameType을 newContext를 사용하여 프레임 유형 가져오기를 실행한 결과로 둔다.

      4. visibilityState를 newContext의 활성 문서의 visibilityState 속성 값으로 둔다.

      5. focusState를 newContext의 활성 문서를 인수로 사용하여 포커스 보유 단계를 실행한 결과로 둔다.

      6. ancestorOriginsList를 newContext의 활성 문서의 상위 출처 목록에 연결된 목록으로 둔다.

      7. serviceWorkerEventLoop에서 DOM 조작 태스크 소스를 사용하여 다음 단계를 실행하도록 태스크를 큐에 추가한다:

        1. newContext의 Window 객체의 환경 설정 객체가 주어졌을 때 저장소 키를 얻기를 실행한 결과가 서비스 워커의 포함하는 서비스 워커 등록의 저장소 키와 같지 않으면, promise를 null로 이행하고 이 단계들을 중단한다.

        2. client를 newContext의 Window 객체의 환경 설정 객체, frameType, visibilityState, focusState, ancestorOriginsList를 인수로 사용하여 윈도우 클라이언트 생성을 실행한 결과로 둔다.

        3. promise를 client로 이행한다.

  8. promise를 반환한다.

4.3.4. claim()

claim() 메서드 단계는 다음과 같다:

  1. 서비스 워커가 활성 워커가 아니면, "InvalidStateError" DOMException으로 거부된 프로미스를 반환한다.

  2. promise를 새로운 프로미스로 둔다.

  3. 다음 하위 단계를 병렬로 실행한다.

    1. client가 주어졌을 때 스토리지 키를 얻기를 실행한 결과가 서비스 워커의 포함 서비스 워커 등록의 스토리지 키와 같은 각 서비스 워커 클라이언트 client에 대해:

      1. client의 실행 준비 플래그가 설정되지 않았거나 client의 폐기 플래그가 설정되어 있으면, 계속한다.

      2. client가 보안 컨텍스트가 아니면, 계속한다.

      3. storage key를 client가 주어졌을 때 스토리지 키를 얻기를 실행한 결과로 둔다.

      4. registration을 storage key와 client의 생성 URL이 주어졌을 때 서비스 워커 등록 일치시키기를 실행한 결과로 둔다.

      5. registration이 서비스 워커의 포함 서비스 워커 등록이 아니면, 계속한다.

        참고: 서비스 워커의 포함 서비스 워커 등록이 등록 해제됨 상태이면 registration은 null이다.

      6. client의 활성 서비스 워커가 서비스 워커가 아니면:

        1. client를 인수로 하여 서비스 워커 클라이언트 언로드 처리를 호출한다.

        2. client의 활성 서비스 워커를 서비스 워커로 설정한다.

        3. client를 인수로 하여 컨트롤러 변경 알림 알고리즘을 호출한다.

    2. task를 큐에 넣어 promise의 relevant settings object의 responsible event loop에서 DOM manipulation task source를 사용하여 promise를 undefined로 resolve한다.

  4. promise를 반환한다.

4.4. ExtendableEvent

[Exposed=ServiceWorker]
interface ExtendableEvent : Event {
  constructor(DOMString type, optional ExtendableEventInit eventInitDict = {});
  undefined waitUntil(Promise<any> f);
};
dictionary ExtendableEventInit : EventInit {
  // Defined for the forward compatibility across the derived events
};

ExtendableEvent 객체는 수명 연장 프라미스(프라미스 배열)을 가지고 있다. 최초에는 빈 배열이다.

ExtendableEvent 객체는 대기 중 프라미스 수(수명 연장 프라미스 중 대기 중인 프라미스의 수)을 가지고 있다. 최초에는 0으로 설정된다.

ExtendableEvent 객체는 타임아웃 플래그를 가진다. 최초에는 설정되지 않으며, 대기 중 프라미스 수가 0보다 크면 사용자 에이전트가 부여한 선택적 지연 후에 설정된다.

ExtendableEvent 객체는 활성 상태라고 하는데, 이는 타임아웃 플래그가 설정되지 않았고, 대기 중 프라미스 수가 0보다 크거나 dispatch 플래그가 설정된 경우이다.

서비스 워커는 두 개의 라이프사이클 이벤트(install 및 activate)를 갖는다. 서비스 워커는 ExtendableEvent 인터페이스를 activate 및 install 이벤트에 사용한다.

서비스 워커 확장에서 이벤트 핸들러를 정의하는 경우에는 ExtendableEvent 인터페이스를 사용할 수도 있고, 확장할 수도 있다.

4.4.1. event.waitUntil(f)

참고: waitUntil() 메서드는 이벤트의 수명을 연장한다.

waitUntil(f) 메서드 단계는 수명 연장 프라미스 추가 f를 this에 추가하는 것이다.

수명 연장 프라미스 추가 promise(프라미스)를 event(ExtendableEvent)에 추가하려면 다음 단계들을 실행한다:
  1. event의 isTrusted 속성이 false이면, "InvalidStateError" DOMException을 throw한다.

  2. event가 활성 상태가 아니면, "InvalidStateError" DOMException을 throw한다.

    참고: 이벤트 핸들러를 호출한 태스크에서 수명 연장 프라미스가 추가되지 않았다면, 이후 비동기 태스크에서 waitUntil()을 호출하면 예외가 발생한다.

  3. promise를 event의 수명 연장 프라미스에 추가한다.

  4. event의 대기 중 프라미스 수를 1 증가시킨다.

    참고: 주어진 프라미스가 이미 settle된 경우에도 대기 중 프라미스 수는 증가한다. 해당 카운트 감소는 프라미스 반응의 미크로태스크에서 처리된다.

  5. promise가 이행 또는 거부될 때, 미크로태스크를 큐에 추가하여 다음 하위 단계들을 실행한다:

    1. event의 대기 중 프라미스 수를 1 감소시킨다.

    2. event의 대기 중 프라미스 수가 0이면:

      1. registration을 현재 글로벌 객체의 서비스 워커의 등록 객체로 한다.

      2. registration이 등록 해제됨이면, Try Clear Registration을 registration을 인수로 실행한다.

      3. registration이 null이 아니면, Try Activate를 registration을 인수로 실행한다.

사용자 에이전트는 서비스 워커에 대기 중 이벤트 없음이 서비스 워커에 대해 false를 반환하면 해당 서비스 워커를 종료하지 않아야 한다.

서비스 워커와 확장 기능이 이벤트 핸들러를 정의하는 경우, 자체 동작을 정의할 수 있으며, extend lifetime promises로 연산의 지속 시간을 제안하거나, 프라미스(promise)의 거부 상태를 통해 extend lifetime promises에서 연산 실패를 알릴 수 있습니다.

참고: 서비스 워커는 설치 중인 워커를 "installed" 상태로 간주하는 것을, install 이벤트의 extend lifetime promises에 속한 모든 프라미스가 성공적으로 resolve될 때까지 지연합니다. (관련 설치 알고리즘 단계 참고.) 만약 어떤 프라미스라도 reject된다면, 설치는 실패합니다. 이는 주로 서비스 워커가 의존하는 필수 캐시가 모두 채워지기 전까지 "installed"로 간주되지 않도록 하기 위함입니다. 마찬가지로, 서비스 워커는 active worker를 "activated" 상태로 간주하는 것을, activate 이벤트의 extend lifetime promises에 속한 모든 프라미스가 settle될 때까지 지연합니다. (관련 activate 알고리즘 단계 참고.) 이는 기능성 이벤트가 해당 서비스 워커에 디스패치되기 전에 데이터베이스 스키마가 업그레이드되고, 오래된 캐시 항목이 삭제될 수 있도록 보장하기 위한 것입니다.

4.5. InstallEvent

[Exposed=ServiceWorker]
interface InstallEvent : ExtendableEvent {
  constructor(DOMString type, optional ExtendableEventInit eventInitDict = {});
  Promise<undefined> addRoutes((RouterRule or sequence<RouterRule>) rules);
};

dictionary RouterRule {
  required RouterCondition condition;
  required RouterSource source;
};

dictionary RouterCondition {
  URLPatternCompatible urlPattern;
  ByteString requestMethod;
  RequestMode requestMode;
  RequestDestination requestDestination;
  RunningStatus runningStatus;

  sequence<RouterCondition> _or;
  RouterCondition not;
};

typedef (RouterSourceDict or RouterSourceEnum) RouterSource;

dictionary RouterSourceDict {
  DOMString cacheName;
};

enum RunningStatus { "running", "not-running" };
enum RouterSourceEnum {
  "cache",
  "fetch-event",
  "network",
  "race-network-and-fetch-handler"
};

라우터 조건 결과 카운트는 구조체이며 다음으로 구성된다:

  • 조건 카운트(숫자).

  • 쿼터 초과(불리언).

4.5.1. event.addRoutes(rules)

참고: addRoutes(rules) 메서드는 이 서비스 워커를 위해 fetch 이벤트 핸들러가 일반적으로 하는 단순 작업을 오프로드할 규칙을 등록한다.

addRoutes(rules) 메서드 단계는 다음과 같다:

  1. rules가 RouterRule 딕셔너리이면, rules를 « rules »로 설정한다.

  2. serviceWorker를 current global object의 연관된 service worker로 둔다.

  3. rules의 각 rule에 대해:

    1. Verify Router Condition 알고리즘을 rule["condition"] 및 serviceWorker와 함께 실행한 결과가 false를 반환하면, a promise rejected with a TypeError를 반환한다.

    2. rule["source"]가 "fetch-event" 또는 "race-network-and-fetch-handler" 중 하나이고, serviceWorker의 set of event types to handle에 fetch가 포함되어 있지 않으면, a promise rejected with a TypeError를 반환한다.

  4. lifetimePromise를 새로운 promise로 둔다.

  5. Add lifetime promise lifetimePromise를 this에 추가한다.

    Note: event.addRoutes(rules)는 기본적으로 event.waitUntil(promise)가 호출된 것처럼 이벤트의 수명을 연장한다.

  6. promise를 새로운 promise로 둔다.

  7. promise가 이행되거나 거부되면, lifetimePromise를 undefined로 resolve한다.

    Note: 이 단계는 install 이벤트 실패를 피하기 위해 lifetimePromise가 항상 이행되도록 하기 위한 것이다.

  8. serviceWorkerEventLoop를 current global object의 event loop로 둔다.

  9. 다음 단계를 Enqueue하여 [[service worker queue]]에 넣는다:

    1. allRules를 serviceWorker의 list of router rules의 복사본으로 둔다.

    2. rules의 각 rule에 대해:

      1. rule을 allRules에 추가한다.

    3. Check Router Registration Limit을 allRules와 함께 실행한 결과가 false이면, 다음을 수행한다:

      1. task를 큐에 넣어 다음 단계를 serviceWorkerEventLoop에서 DOM manipulation task source를 사용해 실행한다:

        1. promise를 TypeError로 reject한다.

      2. 이 단계들을 중단한다.

    4. serviceWorker의 list of router rules를 allRules로 설정한다.

    5. task를 큐에 넣어 다음 단계를 serviceWorkerEventLoop에서 DOM manipulation task source를 사용해 실행한다:

      1. promise를 undefined로 resolve한다.

  10. promise를 반환한다.

4.6. FetchEvent

[Exposed=ServiceWorker]
interface FetchEvent : ExtendableEvent {
  constructor(DOMString type, FetchEventInit eventInitDict);
  [SameObject] readonly attribute Request request;
  readonly attribute Promise<any> preloadResponse;
  readonly attribute DOMString clientId;
  readonly attribute DOMString resultingClientId;
  readonly attribute DOMString replacesClientId;
  readonly attribute Promise<undefined> handled;

  undefined respondWith(Promise<Response> r);
};
dictionary FetchEventInit : ExtendableEventInit {
  required Request request;
  Promise<any> preloadResponse;
  DOMString clientId = "";
  DOMString resultingClientId = "";
  DOMString replacesClientId = "";
  Promise<undefined> handled;
};

서비스 워커는 필수 기능성 이벤트 fetch를 가진다. fetch 이벤트에 대해, 서비스 워커는 FetchEvent 인터페이스를 사용하며, 이 인터페이스는 ExtendableEvent 인터페이스를 확장한다.

FetchEvent 인터페이스를 사용하는 각 이벤트는 잠재적 응답(response)을 갖고, 초깃값은 null이며 다음의 플래그들도 갖는다(초기값은 모두 unset):

  • 응답 대기 플래그

  • respondWith 진입 플래그

  • respondWith 오류 플래그

4.6.1. event.request

request 속성은 반드시 초기화된 값을 반환해야 한다.

4.6.2. event.preloadResponse

preloadResponse 속성은 반드시 초기화된 값을 반환해야 한다. 이벤트가 생성될 때 해당 속성은 반드시 undefined로 resolve된 promise로 초기화되어야 한다.

4.6.3. event.clientId

clientId 속성은 반드시 초기화된 값을 반환해야 한다. 이벤트가 생성될 때 해당 속성은 반드시 빈 문자열로 초기화되어야 한다.

참고: clientId는 요청에 이를 시작한 서비스 워커 클라이언트가 있는 경우 request의 클라이언트의 ID이며, 그 밖의 경우에는 빈 문자열이다(예: 시작자가 없는 최상위 탐색 요청). 탐색 요청의 결과 문서와 연결된 환경은 resultingClientId를 참조한다.

4.6.4. event.resultingClientId

resultingClientId 속성은 반드시 초기화된 값을 반환해야 한다. 이벤트가 생성될 때 해당 속성은 반드시 빈 문자열로 초기화되어야 한다.

참고: resultingClientId는 request의 예약된 클라이언트의 ID이다. 하위 리소스 요청, 대상이 "report"인 요청, 그리고 request의 예약된 클라이언트가 null인 경우에는 빈 문자열이다.

4.6.5. event.replacesClientId

replacesClientId 속성은 반드시 초기화된 값을 반환해야 한다. 이벤트가 생성될 때 해당 속성은 반드시 빈 문자열로 초기화되어야 한다.

4.6.6. event.handled

handled 속성은 반드시 초기화된 값을 반환해야 한다. 이벤트가 생성될 때 해당 속성은 반드시 pending 상태의 promise로 초기화되어야 한다.

4.6.7. event.respondWith(r)

참고: 개발자는 r 인수에 promise나 Response 객체를 직접 넣을 수 있다(Response 객체는 자동으로 promise로 캐스팅됨). 그렇지 않으면 네트워크 에러가 Fetch로 반환된다. 렌더러 측 보안 검사는 cross-origin 콘텐츠의 tainting과 관련이 있으며 filtered responses 타입에 따라 결정된다(Fetch 참고).

respondWith(r) 메서드 단계는 다음과 같다:

  1. event를 this로 한다.

  2. event의 dispatch 플래그가 unset이면, "InvalidStateError" DOMException을 throw한다.

  3. event의 respondWith 진입 플래그가 설정되어 있으면, "InvalidStateError" DOMException을 throw한다.

  4. 수명 연장 프라미스 추가 r를 event에 추가한다.

    참고: event.respondWith(r) 호출은 event.waitUntil(r)과 같이 이벤트의 수명을 기본적으로 연장한다.

  5. event의 stop propagation 플래그와 stop immediate propagation 플래그를 설정한다.

  6. event의 respondWith 진입 플래그를 설정한다.

  7. event의 응답 대기 플래그를 설정한다.

  8. targetRealm을 event의 relevant Realm으로 한다.

  9. r가 reject될 때:

    1. event의 respondWith 오류 플래그를 설정한다.

    2. event의 응답 대기 플래그를 unset한다.

  10. r가 이행될 때 response로:

    1. response가 Response 객체가 아니면 respondWith 오류 플래그를 설정한다.

      참고: respondWith 오류 플래그가 설정되면, 네트워크 에러가 Fetch로 Handle Fetch 알고리즘을 통해 반환된다(21.1단계 참고). 그렇지 않으면 response 값이 Fetch로 Handle Fetch 알고리즘을 통해 반환된다(22.1단계 참고).

    2. 그 외에는:

      1. bytes를 빈 바이트 시퀀스로 한다.

      2. end-of-body를 false로 한다.

      3. done을 false로 한다.

      4. potentialResponse를 response의 연관 response의 복사본으로 하되, body는 제외한다.

      5. response의 body가 null이 아니면, 다음 하위 단계를 실행한다:

        1. reader를 reader 얻기를 response의 body의 stream에 대해 실행한 결과로 한다.

        2. pullAlgorithm을 다음 단계들을 실행하는 액션으로 한다:

          1. readRequest를 새로운 read request로 하고, 다음 항목을 포함한다:

            chunk 단계, chunk가 주어졌을 때
            1. 단언: chunk는 Uint8Array이다.

            2. chunk가 나타내는 바이트를 bytes에 추가한다.

            3. potentialResponse의 body info의 encoded size를 bytes의 byte length만큼 증가시킨다.

            4. potentialResponse의 body info의 decoded size를 bytes의 byte length만큼 증가시킨다.

            5. ! DetachArrayBuffer(chunk.[[ViewedArrayBuffer]])를 수행한다.

            close 단계
            1. end-of-body를 true로 한다.

            error 단계
            1. newStream을 에러 처리(TypeError 사용).

          2. reader에서 chunk 읽기를 readRequest로 실행한다.

        3. cancelAlgorithm을 reader cancel을 실행하는 액션으로 한다.

        4. highWaterMark를 사용자 에이전트가 선택한 0 이상의 NaN이 아닌 값으로 한다.

        5. sizeAlgorithm을 chunk 객체를 받아서 0 이상의 NaN/무한대가 아닌 값을 반환하는 알고리즘으로 한다(사용자 에이전트가 선택).

        6. newStream을 ReadableStream의 새 인스턴스로 만들고, set up에 pullAlgorithm pullAlgorithm, cancelAlgorithm cancelAlgorithm, highWaterMark highWaterMark, sizeAlgorithm sizeAlgorithm을 targetRealm에서 실행한다.

        7. potentialResponse의 body를, body의 새 인스턴스로 하고 그 stream을 newStream으로 한다.

        8. done이 false인 동안 반복적으로 다음 하위 단계를 병렬로 실행한다:

          1. newStream이 errored면 done을 true로 한다.

          2. 그 외에 bytes가 비어 있고 end-of-body가 true면, newStream 닫기를 하고 done을 true로 한다.

          3. 그 외에 bytes가 비어 있지 않으면 다음 하위 단계를 실행한다:

            1. chunk를 bytes 처음부터의 부분 시퀀스로 한다.

            2. chunk를 bytes에서 제거한다.

            3. buffer를 ArrayBuffer의 새 인스턴스로 만들고, targetRealm에서 chunk를 담는다.

            4. newStream에 enqueue한다. Uint8Array로 targetRealm에서 buffer를 감싼다.

        참고: 이 단계들은 response의 body의 stream을 potentialResponse에 "파이프"하는 것과 동등한 observable 결과를 만든다.

        참고: 서비스 워커가 chunk 단위로 쓴 데이터는 클라이언트가 동일 chunk 단위로 읽는다고 보장되지 않는다. 즉, 클라이언트는 동일 데이터를 읽지만 chunk 분할은 브라우저에 따라 다를 수 있다.

      6. event의 잠재적 응답을 potentialResponse로 한다.

    3. event의 응답 대기 플래그를 unset한다.

4.7. ExtendableMessageEvent

[Exposed=ServiceWorker]
interface ExtendableMessageEvent : ExtendableEvent {
  constructor(DOMString type, optional ExtendableMessageEventInit eventInitDict = {});
  readonly attribute any data;
  readonly attribute USVString origin;
  readonly attribute DOMString lastEventId;
  [SameObject] readonly attribute (Client or ServiceWorker or MessagePort)? source;
  readonly attribute FrozenArray<MessagePort> ports;
};
dictionary ExtendableMessageEventInit : ExtendableEventInit {
  any data = null;
  USVString origin = "";
  DOMString lastEventId = "";
  (Client or ServiceWorker or MessagePort)? source = null;
  sequence<MessagePort> ports = [];
};

각 ExtendableMessageEvent는 origin (원본(origin), 문자열 또는 null)을 가지며, 처음에는 null로 설정됩니다.

서비스 워커는 이벤트의 생명주기를 확장하기 위해 extendable message 이벤트를 정의합니다. message 이벤트에 대해서는, 서비스 워커가 ExtendableMessageEvent 인터페이스를 사용하며, 이 인터페이스는 ExtendableEvent 인터페이스를 상속합니다.

4.7.1. event.data

data 속성은 초기화된 값을 반환해야 합니다. 객체가 생성될 때 이 속성은 null로 초기화되어야 합니다. 이 속성은 전송되는 메시지를 나타냅니다.

4.7.2. event.origin

origin 속성은 메시지를 보낸 서비스 워커 클라이언트의 출처를 나타낸다.

origin getter 단계는 다음과 같습니다:

  1. this의 origin이 origin이라면, this의 origin의 직렬화 문자열을 반환합니다.

  2. this의 origin이 null이라면 빈 문자열을 반환합니다.

  3. this의 origin 값을 반환합니다.

origin 속성이 “초기화”될 때 (예: ExtendableMessageEvent 컨스트럭터 내), 초기화 값이 객체의 origin에 저장됩니다.

4.7.3. event.lastEventId

lastEventId 속성은 초기화된 값을 반환해야 합니다. 객체가 생성될 때, 이 속성은 빈 문자열로 초기화되어야 합니다.

ExtendableMessageEvent 인터페이스를 구현하는 객체의 origin 추출 단계는 this의 origin이 origin일 경우 반환하고, 아니면 null 반환합니다.

4.7.4. event.source

source 속성은 초기화된 값을 반환해야 합니다. 객체가 생성될 때 이 속성은 null로 초기화되어야 합니다. 이 속성은 메시지를 보낸 Client 객체를 나타냅니다.

4.7.5. event.ports

ports 속성은 초기화된 값을 반환해야 합니다. 객체가 생성될 때 이 속성은 빈 배열로 초기화되어야 합니다. 이 속성은 전송되는 MessagePort 배열을 나타냅니다.

4.8. 이벤트

다음 이벤트들은 서비스 워커 이벤트라고 하며, ServiceWorkerGlobalScope 객체에서 발생합니다:

이벤트 이름 인터페이스 범주 디스패치되는 시점…
install InstallEvent 수명 주기 서비스 워커의 포함 서비스 워커 등록의 설치 중인 워커가 변경될 때. (설치 알고리즘의 11.2단계를 참조한다.)
activate ExtendableEvent 수명 주기 서비스 워커의 포함 서비스 워커 등록의 활성 워커가 변경될 때. (활성화 알고리즘의 12.2단계를 참조한다.)
fetch FetchEvent 기능 HTTP 가져오기가 request로 가져오기 처리를 호출할 때. 가져오기 처리를 수행한 결과, 서비스 워커는 HTTP 가져오기에 응답을 반환한다. Response 객체로 나타내는 응답은 Cache 객체에서 가져오거나 self.fetch(input, init) 메서드를 사용하여 네트워크에서 직접 가져올 수 있다. (사용자 정의 Response 객체를 사용하는 것도 한 가지 방법이다.)
push PushEvent 기능 (푸시 이벤트 발동을 참조한다.)
notificationclick NotificationEvent 기능 (알림 활성화를 참조한다.)
notificationclose NotificationEvent 기능 (알림 닫기를 참조한다.)
sync SyncEvent 기능 (동기화 이벤트 발동을 참조한다.)
canmakepayment CanMakePaymentEvent 기능 (CanMakePaymentEvent 처리를 참조한다.)
paymentrequest PaymentRequestEvent 기능 (PaymentRequestEvent 처리를 참조한다.)
message ExtendableMessageEvent 레거시 메시지를 수신할 때.
messageerror ExtendableMessageEvent 레거시 역직렬화할 수 없는 메시지가 전송되었을 때.

5. 캐시

저자들이 오프라인 사용을 위해 콘텐츠 캐시를 완전히 관리할 수 있도록, Window 및 WorkerGlobalScope 는 비동기 캐싱 메서드를 제공하여 Cache 객체를 열고 조작할 수 있게 합니다. 하나의 origin은 여러 개의 이름이 있는 Cache 객체를 가질 수 있으며, 그 내용은 스크립트가 완전히 제어합니다. 캐시는 origin 간에 공유되지 않고, 브라우저의 HTTP 캐시와 완전히 분리되어 있습니다.

5.1. 구성요소

요청 응답 리스트는 요청(요청)과 응답(응답)으로 구성된 튜플의 리스트이다.

관련 요청 응답 리스트는 this가 나타내는 인스턴스이다.

이름에서 캐시로의 맵은 키(요청 응답 리스트의 이름을 나타내는 문자열)와 값(요청 응답 리스트)으로 구성된 항목을 갖는 정렬된 맵이다.

CacheStorage 객체의 관련 이름에서 캐시로의 맵은 객체의 관련 설정 객체와 "caches"를 사용하여 로컬 스토리지 보틀 맵을 얻는 알고리즘을 실행한 결과와 연결된 이름에서 캐시로의 맵이다.

5.2. 캐시의 수명 이해하기

Cache 인스턴스는 브라우저의 HTTP 캐시의 일부가 아닙니다. Cache 객체는 저자가 직접 관리해야 하는 대상입니다. Cache 객체는 저자가 명시적으로 요청하지 않는 한 업데이트되지 않습니다. Cache 객체는 저자가 항목을 삭제하지 않는 한 만료되지 않습니다. Cache 객체는 서비스 워커 스크립트가 업데이트되어도 사라지지 않습니다. 즉, 캐시는 자동으로 업데이트되지 않으며, 수동으로 관리해야 합니다. 따라서 저자들은 캐시 이름에 버전을 부여하고, 해당 서비스 워커 버전에서만 캐시를 사용해야 합니다.

5.3. self.caches

partial interface mixin WindowOrWorkerGlobalScope {
  [SecureContext, SameObject] readonly attribute CacheStorage caches;
};

5.3.1. caches

caches getter 단계는 this의 연관된 CacheStorage 객체를 반환하는 것입니다.

5.4. Cache

[SecureContext, Exposed=(Window,Worker)]
interface Cache {
  [NewObject] Promise<(Response or undefined)> match(RequestInfo request, optional CacheQueryOptions options = {});
  [NewObject] Promise<FrozenArray<Response>> matchAll(optional RequestInfo request, optional CacheQueryOptions options = {});
  [NewObject] Promise<undefined> add(RequestInfo request);
  [NewObject] Promise<undefined> addAll(sequence<RequestInfo> requests);
  [NewObject] Promise<undefined> put(RequestInfo request, Response response);
  [NewObject] Promise<boolean> delete(RequestInfo request, optional CacheQueryOptions options = {});
  [NewObject] Promise<FrozenArray<Request>> keys(optional RequestInfo request, optional CacheQueryOptions options = {});
};
dictionary CacheQueryOptions {
  boolean ignoreSearch = false;
  boolean ignoreMethod = false;
  boolean ignoreVary = false;
};

Cache 객체는 request response list를 나타냅니다. 문서와 워커에서 Cache 인터페이스를 구현하는 여러 개의 별도 객체가 동시에 동일한 request response list에 연결될 수 있습니다.

cache batch operation은 struct로 구성되며 다음을 포함합니다:

5.4.1. match(request, options)

match(request, options) 메서드 단계는 다음과 같습니다:

  1. promise를 새로운 promise로 둡니다.

  2. 다음 하위 단계를 병렬로 실행합니다:

    1. p를 matchAll(request, options) 메서드에 request와 options를 전달하여 실행한 결과로 둡니다.

    2. p가 완료될 때까지 대기합니다.

    3. p가 예외와 함께 reject되면,

      1. promise를 해당 예외로 reject합니다.

    4. 그렇지 않고 p가 배열 responses로 resolve되면,

      1. responses가 빈 배열이면,

        1. promise를 undefined로 resolve합니다.

      2. 그 외의 경우:

        1. promise를 responses의 첫 번째 요소로 resolve합니다.

  3. promise를 반환합니다.

5.4.2. matchAll(request, options)

matchAll(request, options) 메서드 단계는 다음과 같습니다:

  1. r을 null로 둔다.

  2. 선택적 인수 request가 생략되지 않았으면:

    1. request가 Request 객체이면:

      1. r을 request의 요청으로 설정한다.

      2. r의 메서드가 `GET`이 아니고 options.ignoreMethod가 false이면, 빈 배열로 이행된 프로미스를 반환한다.

    2. 그렇지 않고 request가 문자열이면:

      1. request를 인수로 하여 Request의 초기 값을 생성자로 호출한 결과에 연결된 요청으로 r을 설정한다. 이 과정에서 예외를 던지면, 해당 예외로 거부된 프로미스를 반환한다.

  3. realm을 this의 관련 Realm으로 둔다.

  4. promise를 새 프로미스로 둔다.

  5. 다음 하위 단계를 병렬로 실행한다.

    1. responses를 빈 목록으로 둔다.

    2. 선택적 인수 request가 생략되었으면:

      1. 각 관련 요청 응답 목록의 requestResponse에 대해:

        1. requestResponse의 응답 복사본을 responses에 추가한다.

    3. 그렇지 않으면:

      1. requestResponses를 r과 options로 캐시 질의를 실행한 결과로 둔다.

      2. 각 requestResponses의 requestResponse에 대해:

        1. requestResponse의 응답 복사본을 responses에 추가한다.

    4. responses의 각 response에 대해:

      1. response의 type이 "opaque"이고 promise의 relevant settings object의 origin, promise의 relevant settings object, "", 그리고 response의 internal response로 cross-origin resource policy check를 수행한 결과가 blocked를 반환하면, promise를 TypeError로 reject하고 이 단계들을 중단한다.

    5. task를 큐에 넣어, promise의 relevant settings object의 responsible event loop에서 DOM manipulation task source를 사용해 다음 단계를 수행한다:

      1. responseList를 list로 둔다.

      2. responses의 각 response에 대해:

        1. response와 연관된 새 Response 객체와, guard가 "immutable"인 새 Headers 객체를 responseList에 추가한다.

      3. realm에서 responseList로부터 생성된 frozen array로 promise를 resolve한다.

  6. promise를 반환한다.

5.4.3. add(request)

add(request) 메서드 단계는 다음과 같습니다:

  1. requests를 request만을 포함하는 배열로 둡니다.

  2. responseArrayPromise를 addAll(requests) 알고리즘에 requests를 인자로 전달하여 실행한 결과로 둡니다.

  3. responseArrayPromise가 fulfill될 때 undefined를 반환하는 fulfillment handler와 함께 reacting한 결과를 반환합니다.

5.4.4. addAll(requests)

addAll(requests) 메서드 단계는 다음과 같습니다:

  1. responsePromises를 빈 리스트로 둔다.

  2. requestList를 빈 리스트로 둔다.

  3. requests에서 유형이 Request인 각 request에 대해:

    1. r을 request의 요청으로 둔다.

    2. r의 URL의 스킴이 "http"와 "https" 중 하나가 아니거나, r의 메서드가 `GET`이 아니면, TypeError로 거부된 프로미스를 반환한다.

  4. fetchControllers를 가져오기 컨트롤러의 리스트로 둔다.

  5. requests의 각 request에 대해:

    1. r을 request를 인수로 사용하여 Request의 초기 값을 생성자로 호출한 결과와 연결된 요청으로 둔다. 이것이 예외를 던지면, 해당 예외로 거부된 프로미스를 반환한다.

    2. r의 URL의 스킴이 "http"와 "https" 중 하나가 아니면:

      1. fetchControllers의 각 fetchController에 대해 반복하여, fetchController를 중단한다.

      2. TypeError로 거부된 프로미스를 반환한다.

    3. r의 클라이언트의 전역 객체가 ServiceWorkerGlobalScope 객체이면, request의 서비스 워커 모드를 "none"으로 설정한다.

    4. r을 requestList에 추가한다.

    5. responsePromise를 새 프로미스로 둔다.

    6. 다음 하위 단계를 병렬로 실행한다.

      • r을 가져온 결과를 추가한다.

      • response에 대한 processResponse로서 다음 하위 단계를 실행한다.

        1. response의 유형이 "error"이거나, response의 상태가 정상 상태가 아니거나 206이면, responsePromise를 TypeError로 거부한다.

        2. 그렇지 않고 response의 헤더 리스트에 `Vary`라는 이름의 헤더가 포함되어 있으면:

          1. fieldValues를 Vary 헤더의 필드 값에 해당하는 요소를 포함하는 리스트로 둔다.

          2. fieldValues의 각 fieldValue에 대해 반복한다.

            1. fieldValue가 "*"와 일치하면:

              1. responsePromise를 TypeError로 거부한다.

              2. fetchControllers의 각 fetchController에 대해 반복하여, fetchController를 중단한다.

              3. 이 단계를 중단한다.

      • response에 대한 processResponseEndOfBody로서 다음 하위 단계를 실행한다.

        1. response의 중단됨 플래그가 설정되어 있으면, responsePromise를 "AbortError" DOMException으로 거부하고 이 단계를 중단한다.

        2. responsePromise를 response로 이행한다.

        참고: 응답의 본문이 완전히 수신되면 캐시 커밋이 허용된다.

    7. responsePromise를 responsePromises에 추가한다.

  6. p를 responsePromises의 모든 항목을 기다리는 프로미스를 얻은 결과로 둔다.

  7. p에 반응한 결과를 반환한다. 이때 이행 핸들러는 인수 responses로 호출되면 다음 하위 단계를 수행한다.

    1. operations를 빈 목록으로 둔다.

    2. index를 0으로 둔다.

    3. responses의 각 response에 대해:

      1. operation을 캐시 일괄 작업으로 둔다.

      2. operation의 유형을 "put"으로 설정한다.

      3. operation의 요청을 requestList[index]로 설정한다.

      4. operation의 응답을 response로 설정한다.

      5. operation을 operations에 추가한다.

      6. index를 1 증가시킨다.

    4. realm을 this의 관련 Realm으로 둔다.

    5. cacheJobPromise를 새 프로미스로 둔다.

    6. 다음 하위 단계를 병렬로 실행한다.

      1. errorData를 null로 둔다.

      2. Batch Cache Operations를 operations와 함께 호출한다. 이 과정에서 예외를 던지면, errorData를 해당 예외로 설정한다.

      3. task를 큐에 넣어, cacheJobPromise의 relevant settings object의 responsible event loop에서 DOM manipulation task source를 사용하여 다음 하위 단계를 수행한다:

        1. errorData가 null이면, cacheJobPromise를 undefined로 resolve한다.

        2. 그렇지 않으면, realm에서 errorData로 새로 생성된 exception으로 cacheJobPromise를 reject한다.

    7. cacheJobPromise를 반환한다.

5.4.5. put(request, response)

put(request, response) 메서드 단계는 다음과 같습니다:

  1. innerRequest를 null로 둔다.

  2. 만약 request가 Request 객체라면, innerRequest를 request의 request로 설정한다.

  3. 그렇지 않으면:

    1. requestObj를 Request의 생성자에 request를 인자로 넘겨 호출한 결과로 둔다. 만약 이것이 예외(exception)를 발생시키면, 해당 예외와 함께 거부된 프라미스를 반환한다.

    2. innerRequest를 requestObj의 request로 설정한다.

  4. 만약 innerRequest의 url의 scheme이 "http"와 "https" 중 하나가 아니거나, innerRequest의 method가 `GET`이 아니라면, TypeError와 함께 거부된 프라미스를 반환한다.

  5. innerResponse를 response의 response로 둔다.

  6. 만약 innerResponse의 status가 206이라면, TypeError와 함께 거부된 프라미스를 반환한다.

  7. 만약 innerResponse의 header list에 header 이름이 `Vary`인 항목이 있다면:

    1. fieldValues를 리스트(list)로, 해당 아이템이 Vary 헤더의 필드 값(field-values)을 포함하도록 한다.

    2. 각 fieldValue에 대하여 fieldValues에서:

      1. 만약 fieldValue가 "*"와 일치한다면, TypeError와 함께 거부된 프라미스를 반환한다.

  8. 만약 innerResponse의 body가 disturbed 상태이거나, locked 상태라면, TypeError와 함께 거부된 프라미스를 반환한다.

  9. clonedResponse를 innerResponse의 복제(clone)로 둔다.

  10. bodyReadPromise를 undefined로 resolve된 프라미스로 한다.

  11. 만약 innerResponse의 body가 null이 아니라면, 다음 하위 단계를 실행한다:

    1. stream을 innerResponse의 body의 stream으로 둔다.

    2. reader를 stream에 대해 reader 얻기의 결과로 한다.

    3. bodyReadPromise를 reader로부터 모든 바이트를 읽는 결과로 설정한다.

    참고: 이는 innerResponse의 body가 locked 상태가 되며, clonedResponse에 버퍼링된 전체 본문 복사본이 존재함을 보장한다. 구현에서는 메모리 대신 디스크 스트리밍 최적화가 가능하다.

  12. operations를 빈 리스트로 둔다.

  13. operation을 캐시 배치 작업(cache batch operation)으로 둔다.

  14. operation의 type을 "put"으로 설정한다.

  15. operation의 request를 innerRequest로 설정한다.

  16. operation의 response를 clonedResponse로 설정한다.

  17. operation을 operations에 추가(append)한다.

  18. realm을 this의 관련 realm으로 둔다.

  19. bodyReadPromise의 이행(fulfillment) 결과를 반환한다:

    1. cacheJobPromise를 새로운 프라미스로 둔다.

    2. cacheJobPromise를 반환하고, 다음 단계를 병렬로 실행:

      1. errorData를 null로 둔다.

      2. operations를 사용하여 캐시 작업 일괄 처리를 호출한다. 이 호출이 예외를 던지면, errorData를 해당 예외로 설정한다.

      3. cacheJobPromise의 관련 설정 객체의 담당 이벤트 루프에서 DOM 조작 태스크 소스를 사용하여, 다음 하위 단계를 수행하도록 태스크를 큐에 넣는다:

        1. errorData가 null이면, cacheJobPromise를 undefined로 이행한다.

        2. 그렇지 않으면 realm에서 errorData를 사용하여 새 예외를 생성하고, 이를 사용하여 cacheJobPromise를 거부한다.

5.4.6. delete(request, options)

delete(request, options) 메서드 단계는 다음과 같습니다:

  1. r을 null로 둡니다.

  2. request가 Request 객체라면:

    1. r에 request의 request를 설정합니다.

    2. r의 method가 `GET`이 아니고 options.ignoreMethod가 false인 경우, false로 resolve된 promise를 반환합니다.

  3. 그 외에 request가 문자열이라면:

    1. r을 Request 생성자에 request를 인자로 하여 얻은 결과의 관련 request로 설정합니다. 만약 예외가 발생하면 해당 예외로 reject된 promise를 반환합니다.

  4. operations를 빈 리스트로 둡니다.

  5. operation을 캐시 배치 작업(cache batch operation)으로 둡니다.

  6. operation의 type을 "delete"로 설정합니다.

  7. operation의 request를 r로 설정합니다.

  8. operation의 options를 options로 설정합니다.

  9. Append를 통해 operation을 operations에 추가합니다.

  10. realm을 this의 관련 realm으로 둡니다.

  11. cacheJobPromise를 새로운 promise로 둡니다.

  12. 다음 하위 단계를 병렬로 실행합니다:

    1. errorData를 null로 둔다.

    2. requestResponses를 operations로 캐시 작업 일괄 수행을 실행한 결과로 둔다. 이 과정에서 예외를 던지면, errorData를 해당 예외로 설정한다.

    3. task를 큐에 넣어, cacheJobPromise의 relevant settings object의 responsible event loop에서 DOM manipulation task source를 사용해 다음 하위 단계를 수행한다:

      1. errorData가 null이면:

        1. requestResponses가 비어 있지 않으면, cacheJobPromise를 true로 이행한다.

        2. 그렇지 않으면, cacheJobPromise를 false로 이행한다.

      2. 그렇지 않으면, realm에서 errorData를 사용하여 새로 생성한 예외로 cacheJobPromise를 거부한다.

  13. cacheJobPromise를 반환합니다.

5.4.7. keys(request, options)

keys(request, options) 메서드 단계는 다음과 같습니다:

  1. r을 null로 둡니다.

  2. 선택적 인자인 request가 생략되지 않았다면:

    1. request가 Request 객체라면:

      1. r을 request의 request로 설정합니다.

      2. r의 method가 `GET`이 아니고 options.ignoreMethod가 false인 경우, 빈 배열로 resolve된 promise를 반환합니다.

    2. 그 외에 request가 문자열이라면:

      1. r을 Request 생성자에 request를 인자로 하여 얻은 결과의 관련 request로 설정합니다. 만약 예외가 발생하면, 해당 예외로 reject된 promise를 반환합니다.

  3. realm을 this의 관련 realm으로 둡니다.

  4. promise를 새로운 promise로 둡니다.

  5. 다음 하위 단계를 병렬로 실행합니다:

    1. requests를 빈 리스트로 둡니다.

    2. 선택적 인자인 request가 생략된 경우,

      1. 각 requestResponse를 relevant request response list에서 반복하여:

        1. requestResponse의 request를 requests에 추가합니다.

    3. 그 외의 경우:

      1. requestResponses를 Query Cache에 r과 options를 전달하여 실행한 결과로 둡니다.

      2. 각 requestResponse를 requestResponses에서 반복하여:

        1. requestResponse의 request를 requests에 추가합니다.

    4. task를 큐에 넣어, promise의 relevant settings object의 responsible event loop에서 DOM manipulation task source를 사용해 다음 단계를 수행한다:

      1. requestList를 리스트로 둡니다.

      2. 각 request를 requests에서 반복하여:

        1. request와 Headers 객체(해당 guard가 "immutable"인 새 객체)를 연결하여 새로운 Request 객체를 requestList에 추가합니다.

      3. promise를 frozen array로 생성된 requestList로, realm에서 resolve합니다.

  6. promise를 반환합니다.

5.5. CacheStorage

[SecureContext, Exposed=(Window,Worker)]
interface CacheStorage {
  [NewObject] Promise<(Response or undefined)> match(RequestInfo request, optional MultiCacheQueryOptions options = {});
  [NewObject] Promise<boolean> has(DOMString cacheName);
  [NewObject] Promise<Cache> open(DOMString cacheName);
  [NewObject] Promise<boolean> delete(DOMString cacheName);
  [NewObject] Promise<sequence<DOMString>> keys();
};

dictionary MultiCacheQueryOptions : CacheQueryOptions {
  DOMString cacheName;
};

참고: CacheStorage 인터페이스는 주로 ECMAScript 6 Map 객체와 일치하도록 설계되었으나, 완전히 비동기적이며 추가적인 편의 메서드를 포함합니다. clear, forEach, entries, values 메서드는 TC39의 비동기 반복자 논의가 계속되고 있기 때문에 일부러 첫 번째 버전의 범위에서 제외되었습니다.

사용자 에이전트는 CacheStorage 객체를 Window 객체나 WorkerGlobalScope 객체가 생성될 때 반드시 생성해야 합니다.

CacheStorage 객체는 자신의 name to cache map을 나타내며, 이 맵은 객체의 로컬 스토리지 병 맵 얻기를 관련 설정 객체와 "caches"를 인자로 실행한 결과와 연관됩니다. 여러 문서와 워커에서 CacheStorage 인터페이스를 구현하는 별개의 객체들이 동시에 동일한 name to cache map과 연관될 수 있습니다.

5.5.1. match(request, options)

match(request, options) 메서드 단계는 다음과 같습니다:

  1. 만약 options["cacheName"] 존재한다면,

    1. 새로운 프라미스(promise) promise를 반환하고, 다음 하위 단계를 병렬로 실행한다:

      1. 각 cacheName → cache에 대해 관련 name to cache 맵에서 순회한다:

        1. 만약 options["cacheName"] 이 cacheName에 일치하면,

          1. promise를 Cache 인터페이스의 match(request, options) 메서드에 request와 options를 인자로 넘기고(cache를 match(request, options)의 \[[Call]] 내부 메서드의 thisArgument로 제공) 지정된 알고리즘의 결과로 resolve한다.

          2. 이 단계를 중단한다.

      2. promise를 undefined로 resolve한다.

  2. 그렇지 않으면:

    1. promise를 undefined로 resolve된 프라미스로 둔다.

    2. 각 cacheName → cache에 대해 관련 name to cache 맵에서 순회한다:

      1. promise를, fulfillment 핸들러가 호출될 때(인자로 response를 받음) 다음 하위 단계를 수행하는 방식으로, 자기 자신에 대해 reacting한 결과로 설정한다:

        1. 만약 response가 undefined가 아니라면, response를 반환한다.

        2. Cache 인터페이스의 match(request, options) 메서드에 request와 options를 인자로 넘기고(cache를 match(request, options)의 \[[Call]] 내부 메서드의 thisArgument로 제공) 지정된 알고리즘의 결과로 반환한다.

    3. promise를 반환한다.

5.5.2. has(cacheName)

has(cacheName) 메서드 단계는 다음과 같습니다:

  1. promise를 새로운 프라미스로 둔다.

  2. 다음 하위 단계를 병렬로 실행한다:

    1. 각 key → value에 대해 관련 name to cache 맵을 순회한다:

      1. cacheName이 key와 일치하면, promise를 true로 resolve하고 이 단계를 중단한다.

    2. promise를 false로 resolve한다.

  3. promise를 반환한다.

5.5.3. open(cacheName)

open(cacheName) 메서드 단계는 다음과 같다:

  1. promise를 새로운 프라미스(promise)로 둔다.

  2. 다음 하위 단계를 병렬로 실행한다:

    1. 각 key → value에 대하여, 관련 name to cache map에서 순회한다:

      1. 만약 cacheName이 key와 일치하면:

        1. promise를 value를 나타내는 새로운 Cache 객체로 resolve한다.

        2. 이 단계를 중단한다.

    2. cache를 새로운 request response list로 둔다.

    3. Set 관련 name to cache map[cacheName]을 cache로 설정한다. 이 캐시 쓰기 작업이 할당된 quota 한도를 초과하여 실패한 경우, promise를 QuotaExceededError로 reject하고 이 단계를 중단한다.

    4. promise를 cache를 나타내는 새로운 Cache 객체로 resolve한다.

  3. promise를 반환한다.

5.5.4. delete(cacheName)

delete(cacheName) 메서드 단계는 다음과 같다:

  1. promise를 has(cacheName) 메서드에서 cacheName으로 지정된 알고리즘을 실행한 결과로 둔다.

  2. promise에 fulfillment 핸들러로 reacting(reacting) 한 결과를 반환한다. 이 핸들러는 cacheExists 인자를 받으면 다음 하위 단계를 수행한다:

    1. 만약 cacheExists가 false라면:

      1. false를 반환한다.

    2. cacheJobPromise를 새로운 프라미스로 둔다.

    3. 다음 하위 단계를 병렬로 실행한다:

      1. Remove 관련 name to cache map[cacheName].

      2. cacheJobPromise를 true로 resolve한다.

      참고: 이 단계가 끝난 후, 기존 DOM 객체(즉, 현재 참조된 Cache, Request, Response 객체)는 계속 동작해야 한다.

    4. cacheJobPromise를 반환한다.

5.5.5. keys()

keys() 메서드 단계는 다음과 같다:

  1. promise를 새로운 프라미스로 둔다.

  2. 다음 하위 단계를 병렬로 실행한다:

    1. cacheKeys를 관련 name to cache map의 키를 얻은 결과로 둔다.

      참고: 결과 ordered set에 있는 항목들은 name to cache map에 해당 엔트리가 추가된 순서대로 정렬되어 있다.

    2. promise를 cacheKeys로 resolve한다.

  3. promise를 반환한다.

6. 보안 고려사항

6.1. 보안 컨텍스트

서비스 워커는 보안 컨텍스트에서 실행되어야 한다. 서비스 워커 클라이언트도 서비스 워커 등록을 등록하고, 서비스 워커 등록 및 서비스 워커에 접근하며, 서비스 워커와 메시지를 주고받고, 서비스 워커에 의해 조작되려면 보안 컨텍스트여야 한다.

참고: 이는 사실상 서비스 워커와 그 서비스 워커 클라이언트가 HTTPS를 통해 호스팅되어야 함을 의미한다. 사용자 에이전트는 개발 목적으로 localhost(요구사항 참조), 127.0.0.0/8 및 ::1/128을 허용할 수 있다. 이 제한의 주된 이유는 비보안 컨텍스트와 관련된 위험으로부터 사용자를 보호하기 위해서이다.

6.2. 콘텐츠 보안 정책

사용자 에이전트가 서비스 워커 실행 알고리즘을 서비스 워커 serviceWorker에 대해 호출할 때:

  • serviceWorker의 스크립트 리소스가 Content-Security-Policy HTTP 헤더와 policy 값을 포함하여 전달되었다면, 사용자 에이전트는 반드시 policy를 적용해야 합니다.

  • serviceWorker의 스크립트 리소스가 Content-Security-Policy-Report-Only HTTP 헤더와 policy 값을 포함하여 전달되었다면, 사용자 에이전트는 반드시 policy를 모니터링해야 합니다.

이러한 제한의 주요 목적은 교차 사이트 스크립팅(XSS)과 같은 다양한 컨텐츠 주입 취약점을 완화하기 위함입니다.

6.3. 오리진 상대성

6.3.1. 오리진 제한

이 절은 규범적이지 않습니다.

서비스 워커는 등록한 클라이언트의 오리진에서 실행됩니다. 주요 응용 프로그램에서 마주할 수 있는 고급 문제 중 하나는 CDN에서 서비스 워커를 호스팅할 수 있는지입니다. 정의상 CDN은 종종 다른 오리진에 위치합니다. 따라서 서비스 워커는 CDN에서 호스팅할 수 없습니다. 대신 importScripts()를 통해 리소스를 포함할 수 있습니다. 이러한 제한의 이유는 서비스 워커 가 악의적인 행위자에게 일시적인 문제를 영구적인 문제로 만들 기회를 제공하기 때문입니다.

6.3.2. importScripts(urls)

importScripts(urls) 메서드가 ServiceWorkerGlobalScope 객체에서 호출되면, 사용자 에이전트는 반드시 해당 ServiceWorkerGlobalScope 객체와 urls를 사용해 워커 글로벌 스코프에 스크립트 가져오기를 수행해야 하며, 다음과 같은 페치 훅 단계를 request request에 대해 수행합니다:

  1. serviceWorker를 request의 client의 글로벌 객체의 서비스 워커로 둡니다.

  2. map을 serviceWorker의 스크립트 리소스 맵으로 둡니다.

  3. url을 request의 url로 둡니다.

  4. serviceWorker의 상태가 "parsed" 또는 "installing"이 아니면:

    1. map[url]이 존재하면 반환하고, 그렇지 않으면 네트워크 오류를 반환합니다.

  5. map[url]이 존재하면:

    1. Append를 통해 url을 serviceWorker의 사용된 스크립트 집합에 추가합니다.

    2. map[url]을 반환합니다.

  6. registration을 serviceWorker의 포함 서비스 워커 등록으로 둡니다.

  7. request의 service-workers mode를 "none"으로 설정합니다.

  8. 다음 중 하나라도 참이면 request의 cache mode를 "no-cache"로 설정합니다:

  9. response를 request에 대해 fetch한 결과로 둡니다.

  10. response의 cache state가 "local"이 아니면, registration의 마지막 업데이트 확인 시간을 현재 시간으로 설정합니다.

  11. response의 unsafe response가 잘못된 import 스크립트 응답이면 네트워크 오류를 반환합니다.

  12. Set을 통해 map[url]에 response를 저장합니다.

  13. Append를 통해 url을 serviceWorker의 사용된 스크립트 집합에 추가합니다.

  14. serviceWorker의 클래식 스크립트 import 플래그를 설정합니다.

  15. response를 반환합니다.

6.4. 교차 오리진 리소스 및 CORS

이 절은 규범적이지 않습니다.

애플리케이션은 CDN이나 기타 오리진에서 가져온 항목들을 캐싱하는 경우가 많습니다. <script>, <img>, <video>, <link> 요소를 사용해 많은 자원을 직접 요청하는 것도 가능합니다. 이런 런타임 협업이 오프라인일 때 깨진다면 크게 제한될 것입니다. 마찬가지로 적절한 CORS 헤더들이 설정되어 있다면 다양한 오리진-외부(origin 외부) 자원들을 fetch로 가져올 수 있습니다. 서비스 워커는 Caches가 fetch와 캐싱을 오리진 외부 항목에 대해 할 수 있도록 하여 이를 가능하게 합니다. 다만 몇 가지 제한이 있습니다. 우선, 같은 오리진 리소스가 Cache에서 Response 객체로 관리되고 해당 response가 기본 필터링 응답(basic filtered response)인 것과 달리, 저장되는 객체는 Response이고, 그 response가 CORS 필터링 응답 또는 Opaque 필터링 응답인 경우입니다. 이 객체들은 event.respondWith(r) 메서드에, Response의 response가 기본 필터링 응답인 경우와 동일하게 전달할 수 있지만, 프로그램적으로 의미 있게 직접 생성할 수 없습니다. 이러한 제한은 플랫폼의 보안 불변성을 보장하기 위해 필요합니다. Caches가 이런 객체들도 저장할 수 있게 함으로써 대부분의 경우 애플리케이션이 구조를 재설계하지 않아도 되게 해줍니다.

6.5. 경로 제한

이 절은 규범적이지 않습니다.

오리진 제한 외에도, 서비스 워커는 서비스 워커 스크립트의 경로에 의해 제한됩니다. 예를 들어 https://www.example.com/~bob/sw.js에 위치한 서비스 워커 스크립트는 scope url https://www.example.com/~bob/에는 등록할 수 있지만, https://www.example.com/ 또는 https://www.example.com/~alice/에는 등록할 수 없습니다. 이는 같은 오리진 내에서 여러 사용자 콘텐츠를 별도의 디렉터리에 분리해 호스팅하는 사이트에 어느 정도 보호를 제공합니다. 그러나 경로 제한은 오리진만큼 강력한 보안 경계로 간주되지 않습니다. 사이트에서는 적절할 경우 서로 다른 오리진을 사용해 사이트의 부분을 안전하게 격리할 것을 권장합니다.

서버는 서비스 워커 스크립트에 Service-Worker-Allowed 헤더를 설정함으로써 경로 제한을 제거할 수 있습니다.

6.6. 서비스 워커 스크립트 요청

이 절은 규범적이지 않습니다.

악의적인 서비스 워커의 등록을 방지하기 위해, 이 명세는 다음을 요구합니다:

6.7. 구현자 고려사항

이 절은 규범적이지 않습니다.

구현자들은 다음을 주의해야 합니다:

  • 플러그인은 서비스 워커를 통해 로드되어서는 안 됩니다. 플러그인은 자체 URL에서 보안 오리진을 얻을 수 있으므로, 임베딩한 서비스 워커가 이를 처리할 수 없습니다. 이런 이유로 Handle Fetch 알고리즘은 <embed> 및 <object> 요청을 fetch 이벤트를 디스패치하지 않고 즉시 네트워크로 폴백합니다.

  • 레거시 네트워킹 스택 코드 중 일부는 서비스 워커와의 상호작용으로 인한 영향을 이해하기 위해 신중한 점검이 필요할 수 있습니다.

6.8. 프라이버시

서비스 워커는 새로운 영구 저장소 기능을 도입합니다. 여기에는 등록 맵(서비스 워커 등록과 그 서비스 워커용), 요청-응답 리스트와 name to cache 맵(캐시 용), 그리고 스크립트 리소스 맵(스크립트 리소스 용)이 포함됩니다. 사용자들이 인가되지 않은 추적 위협으로부터 보호받을 수 있도록, 이러한 영구 저장소는 사용자가 삭제를 의도할 때 가급적 삭제되길 권장하며, 기존 사용자 제어 기능(예: 모든 영구 저장소 전체 삭제)과 호환되기를, 또한 연동되기를 권장합니다.

7. 확장성

서비스 워커 명세는 다른 명세에서 확장할 수 있습니다.

7.1. Service Worker Registration에 바인딩된 API 정의

명세는 API를 서비스 워커 등록에 연결하여, ServiceWorkerRegistration 인터페이스에 부분 인터페이스(partial interface) 정의를 사용해서, 명세별 속성과 메서드를 정의할 수 있습니다:

partial interface ServiceWorkerRegistration {
  // 예시: API 네임스페이스 정의
  readonly attribute APISpaceType APISpace;
  // 예시: 메서드 정의
  Promise<T> methodName(/* 인자 목록 */);
};

7.2. 기능적 이벤트 정의

명세는 기능적 이벤트(functional event)를 ExtendableEvent 인터페이스를 확장하여 정의할 수 있습니다:

// 예: FunctionalEvent 인터페이스 정의
interface FunctionalEvent : ExtendableEvent {
  // 기능성 이벤트 고유 속성과 메서드 추가
};

7.3. 이벤트 핸들러 정의

명세는 기능적 이벤트(functional event)에 해당하는 이벤트 핸들러 속성을 partial interface 정의를 ServiceWorkerGlobalScope 인터페이스에 추가하여 정의할 수 있습니다:

partial interface ServiceWorkerGlobalScope {
  attribute EventHandler onfunctionalevent;
};

7.4. 기능적 이벤트 발생

기능적 이벤트를 서비스 워커 등록의 활성 워커에 디스패치하도록 요청하려면, 명세에서는 가급적 Fire Functional Event를 호출하기를 권장합니다.

부록 A: 알고리즘

다음 정의들은 명세 전반에서 사용되는 사용자 에이전트의 내부 데이터 구조입니다.

등록 맵은 (순서가 있는 맵)으로, 키는 (storage key, 직렬화된 scope url)이고 값은 서비스 워커 등록입니다.

job은 서비스 워커 등록에 대한 register, update, unregister 요청 중 하나의 추상화입니다.

job은 job type을 가지며, register, update, unregister 중 하나입니다.

job은 storage key(storage key)를 가집니다.

job은 scope url(URL)을 가집니다.

job은 script url(URL)을 가집니다.

job은 worker type("classic" 또는 "module")을 가집니다.

job은 update via cache mode("imports", "all", "none") 중 하나입니다.

job은 client(서비스 워커 클라이언트)를 가지며, 초기값은 null입니다.

job은 referrer(URL 또는 null)을 가집니다.

job은 job promise(promise)를 가지며, 초기값은 null입니다.

job은 containing job queue(job queue 또는 null)을 가지며, 초기값은 null입니다.

job은 동등 job 리스트(job 리스트)이며, 초기값은 빈 리스트입니다.

job은 force bypass cache flag를 가지며, 초기값은 unset입니다.

두 job이 동등이려면 job type이 동일해야 하며, 다음 조건을 만족해야 합니다:

job queue는 동시 job 집합의 동기화를 위해 사용되는 thread-safe 큐입니다. job queue는 job을 item으로 포함하며, job queue의 초기값은 비어 있습니다.

scope to job queue map은 키가 scope url(직렬화됨)이고, 값이 job queue인 순서가 있는 맵입니다.

잘못된 import 스크립트 응답은 아래 조건 중 하나를 만족하는 response입니다:

race result는 튜플이며, 구성 요소는 라우팅된 응답(routed response)과 사용된 라우트(used route)이다.

race result에는 라우팅된 응답(routed response)이 연관되어 있으며, 이는 response이다.

race result에는 사용된 라우트(used route)가 연관되어 있으며, 이는 RouterSourceEnum 타입이다.

작업 생성

입력

jobType, 작업 타입

storage key, 스토리지 키

scopeURL, URL

scriptURL, URL

promise, 프라미스

client, 서비스 워커 클라이언트

출력

job, 작업

  1. job을 새로운 작업으로 둔다.

  2. job의 작업 타입을 jobType으로 설정한다.

  3. job의 스토리지 키를 storage key로 설정한다.

  4. job의 scope url을 scopeURL로 설정한다.

  5. job의 script url을 scriptURL로 설정한다.

  6. job의 작업 프라미스를 promise로 설정한다.

  7. job의 클라이언트를 client로 설정한다.

  8. client가 null이 아니면, job의 referrer를 client의 생성 URL로 설정한다.

  9. job을 반환한다.

작업 스케줄

입력

job, 작업

출력

없음

  1. jobQueue를 null로 둔다.

  2. jobScope를 job의 scope url의 직렬화된 값으로 둔다.

  3. scope to job queue map[jobScope]가 존재하지 않으면, scope to job queue map[jobScope]에 새 작업 큐를 설정한다.

  4. jobQueue를 scope to job queue map[jobScope]로 설정한다.

  5. jobQueue가 비어 있으면:

    1. job의 containing job queue를 jobQueue로 설정하고, jobQueue에 job을 enqueue한다.

    2. 작업 실행을 jobQueue로 호출한다.

  6. 그 외의 경우:

    1. lastJob을 jobQueue의 마지막 요소로 둔다.

    2. job이 동등하고 lastJob의 작업 프라미스가 아직 settle되지 않았다면, job을 lastJob의 동등 작업 리스트에 추가한다.

    3. 그 외에는, job의 containing job queue를 jobQueue로 설정하고, jobQueue에 job을 enqueue한다.

작업 실행

입력

jobQueue, 작업 큐

출력

없음

  1. 단언: jobQueue는 비어 있지 않음을 보장한다.

  2. 작업을 큐에 추가하여 다음 단계를 실행한다:

    1. job을 jobQueue의 첫 번째 item으로 둔다.

    2. job의 작업 타입이 register라면, 등록을 job로 병렬로 실행한다.

    3. 그 외에 job의 작업 타입이 update라면, 업데이트를 job로 병렬로 실행한다.

      참고: register 작업과 update 작업의 경우, 사용자 에이전트는 작업 실행을 위한 작업 큐 추가를, 해당 작업을 시작한 문서에서 DOMContentLoaded 이벤트가 디스패치된 이후로 지연시킨다.

    4. 그 외에 job의 작업 타입이 unregister라면, 등록 해제를 job로 병렬로 실행한다.

작업 완료

입력

job, 작업

출력

없음

  1. jobQueue를 job의 containing job queue로 둔다.

  2. 단언: jobQueue의 첫 번째 item이 job임을 보장한다.

  3. jobQueue에서 dequeue한다.

  4. jobQueue가 비어 있지 않으면, 작업 실행을 jobQueue로 호출한다.

작업 프라미스 해결

입력

job, 작업

value, 임의 값

출력

없음

  1. job의 client가 null이 아니면, task를 큐에 넣어, job의 client의 responsible event loop에서 DOM manipulation task source를 사용해 다음 하위 단계를 실행한다:

    1. convertedValue를 null로 둔다.

    2. job의 job type이 register 또는 update 중 하나이면, convertedValue를 service worker registration object를 가져오기를 통해 job의 client에서 value를 나타내는 결과로 설정한다.

    3. 그렇지 않으면, convertedValue를 job의 client의 Realm에서 value로 설정한다.

    4. job의 job promise를 convertedValue로 resolve한다.

  2. job의 list of equivalent jobs에 있는 각 equivalentJob에 대해:

    1. equivalentJob의 client가 null이면, 루프의 다음 반복으로 계속한다.

    2. task를 큐에 넣어, equivalentJob의 client의 responsible event loop에서 DOM manipulation task source를 사용해 다음 하위 단계를 실행한다:

      1. convertedValue를 null로 둔다.

      2. equivalentJob의 job type이 register 또는 update 중 하나이면, convertedValue를 service worker registration object를 가져오기를 통해 equivalentJob의 client에서 value를 나타내는 결과로 설정한다.

      3. 그렇지 않으면, convertedValue를 equivalentJob의 client의 Realm에서 value로 설정한다.

      4. equivalentJob의 job promise를 convertedValue로 resolve한다.

작업 프라미스 거부

입력

job, 작업

errorData, 예외 생성에 필요한 정보

출력

없음

  1. job의 클라이언트가 null이 아니면, job의 클라이언트의 담당 이벤트 루프에서 DOM 조작 태스크 소스를 사용하여 태스크를 큐에 추가해, job의 작업 프로미스를 job의 클라이언트의 Realm에서 errorData를 사용한 새 예외로 거부한다.

  2. job의 동등한 작업 목록에 있는 각 equivalentJob에 대해:

    1. equivalentJob의 클라이언트가 null이면, 계속한다.

    2. equivalentJob의 클라이언트의 담당 이벤트 루프에서 DOM 조작 태스크 소스를 사용하여 태스크를 큐에 추가해, equivalentJob의 작업 프로미스를 equivalentJob의 클라이언트의 Realm에서 errorData를 사용한 새 예외로 거부한다.

등록 시작

입력

scopeURL, URL 또는 실패 또는 null

scriptURL, URL 또는 실패

promise, 프라미스

client, 서비스 워커 클라이언트

referrer, URL

workerType, 워커 타입

updateViaCache, update via cache mode

출력

없음

  1. scriptURL이 실패이면, promise를 TypeError로 reject하고 이 단계를 중단한다.

  2. scriptURL의 fragment를 null로 설정한다.

    참고: 사용자 에이전트는 스크립트 url의 fragment를 저장하지 않는다. 즉, fragment는 서비스 워커 식별에 영향을 주지 않는다.

  3. scriptURL의 scheme이 "http", "https"가 아니면, promise를 TypeError로 reject하고 이 단계를 중단한다.

  4. scriptURL의 path에 포함된 어떤 문자열이 ASCII 대소문자 구분 없이 "%2f", ASCII 대소문자 구분 없이 "%5c"를 포함하면, promise를 TypeError로 reject하고 이 단계를 중단한다.

  5. scopeURL이 null이면, scopeURL을 "./" 문자열과 scriptURL로 파싱한 결과로 설정한다.

    참고: 등록의 기본 scope url은 서비스 워커 스크립트 위치로 설정된다.

  6. scopeURL이 실패이면, promise를 TypeError로 reject하고 이 단계를 중단한다.

  7. scopeURL의 fragment를 null로 설정한다.

    참고: 사용자 에이전트는 scope url의 fragment를 저장하지 않는다. 즉, fragment는 서비스 워커 등록 식별에 영향을 주지 않는다.

  8. scopeURL의 scheme이 "http", "https"가 아니면, promise를 TypeError로 reject하고 이 단계를 중단한다.

  9. scopeURL의 path에 포함된 어떤 문자열이 ASCII 대소문자 구분 없이 "%2f", ASCII 대소문자 구분 없이 "%5c"를 포함하면, promise를 TypeError로 reject하고 이 단계를 중단한다.

  10. storage key를 클라이언트에서 스토리지 키 얻기 결과로 설정한다.

  11. job을 작업 생성을 register, storage key, scopeURL, scriptURL, promise, client로 실행한 결과로 둔다.

  12. job의 워커 타입을 workerType으로 설정한다.

  13. job의 update via cache mode를 updateViaCache로 설정한다.

  14. job의 referrer를 referrer로 설정한다.

  15. 작업 스케줄을 job로 호출한다.

등록

입력

job, 작업

출력

없음

  1. 잠재적으로 신뢰할 수 있는 오리진 알고리즘을 job의 script url의 오리진에 대해 실행한 결과가 Not Trusted이면:

    1. 작업 프라미스 거부를 job과 "SecurityError" DOMException"로 호출한다.

    2. 작업 완료를 job로 호출하고 이 단계를 중단한다.

  2. job의 script url의 오리진과 job의 referrer의 오리진이 동일 오리진이 아니면:

    1. 작업 프라미스 거부를 job과 "SecurityError" DOMException"로 호출한다.

    2. 작업 완료를 job로 호출하고 이 단계를 중단한다.

  3. job의 scope url의 오리진과 job의 referrer의 오리진이 동일 오리진이 아니면:

    1. 작업 프라미스 거부를 job과 "SecurityError" DOMException"로 호출한다.

    2. 작업 완료를 job로 호출하고 이 단계를 중단한다.

  4. registration을 등록 가져오기를 job의 스토리지 키와 job의 scope url로 실행한 결과로 둔다.

  5. registration이 null이 아니면:

    1. newestWorker를 최신 워커 가져오기를 registration에 대해 실행한 결과로 둔다.

    2. newestWorker가 null이 아니고, job의 script url이 newestWorker의 script url과 동등하고, job의 워커 타입이 newestWorker의 type과 같고, job의 update via cache mode 값이 registration의 update via cache mode와 같으면:

      1. 작업 프라미스 해결을 job과 registration으로 호출한다.

      2. 작업 완료를 job로 호출하고 이 단계를 중단한다.

  6. 그 외에는:

    1. 등록 설정 알고리즘을 job의 스토리지 키, job의 scope url, job의 update via cache mode로 실행한다.

  7. 업데이트 알고리즘을 job로 실행한다.

업데이트

입력

job, 작업

출력

없음

  1. registration을 등록 가져오기를 job의 스토리지 키와 job의 scope url로 실행한 결과로 둔다.

  2. registration이 null이면:

    1. 작업 프라미스 거부를 job과 TypeError로 호출한다.

    2. 작업 완료를 job로 호출하고 이 단계를 중단한다.

  3. newestWorker를 최신 워커 가져오기 알고리즘을 registration에 대해 실행한 결과로 둔다.

  4. job의 작업 타입이 update이고, newestWorker가 null이 아니면서 newestWorker의 script url이 동등하지 않으면 job의 script url과:

    1. 작업 프라미스 거부를 job과 TypeError로 호출한다.

    2. 작업 완료를 job로 호출하고 이 단계를 중단한다.

  5. hasUpdatedResources를 false로 둔다.

  6. updatedResourceMap을 순서가 있는 맵으로 두고, 키는 URL이고 값은 응답이다.

  7. job의 워커 타입에 따라 다음 옵션으로 하위 단계를 실행한다:

    "classic"

    클래식 워커 스크립트 가져오기를 job의 직렬화된 script url, job의 클라이언트, "serviceworker", 그리고 이 서비스 워커의 환경 설정 객체로 실행한다.

    "module"

    모듈 워커 스크립트 그래프 가져오기를 job의 직렬화된 script url, job의 클라이언트, "serviceworker", "same-origin", 그리고 이 서비스 워커의 환경 설정 객체로 실행한다.

    아직 생성되지 않은 environment settings object를 사용하는 것은, 구체적인 environment settings object 대신입니다. 이는 서비스 워커가 다른 웹 워커와 다른 고유한 처리 모델을 가지기 때문입니다. HTML 표준의 스크립트 페치 알고리즘은 원래 다른 웹 워커를 위해 설계되었으며, 실행 환경의 environment settings object를 필요로 합니다. 그러나 서비스 워커는 Update 알고리즘에서 스크립트를 별도로 가져온 후, 그 스크립트가 이후 Run Service Worker 알고리즘을 통해 여러 번 실행됩니다.

    HTML의 클래식 워커 스크립트 가져오기 알고리즘과 모듈 워커 스크립트 그래프 가져오기 알고리즘은 job의 클라이언트를 인자로 받는다. job의 클라이언트는 Soft Update 알고리즘에서 전달받을 때 null이다.

    fetch hook 수행에서 request에 대해 다음 단계를 실행한다:

    1. Service-Worker/script를 request의 헤더 리스트에 추가한다.

      참고: Service-Worker 헤더의 정의는 부록 B: 확장 HTTP 헤더를 참조하세요.

    2. 다음 중 하나라도 해당되면 request의 캐시 모드(cache mode)를 "no-cache"로 설정한다:

      참고: 캐시 모드가 "no-cache"로 설정되지 않더라도, 네트워크 계층 단에서 사용자 에이전트는 Cache-Control 헤더의 max-age 값을 따르므로 브라우저 캐시를 우회할 수 있습니다.

    3. request의 service-workers 모드를 "none"으로 설정한다.

    4. 만약 isTopLevel 플래그가 설정되어 있지 않으면, fetching request의 결과를 반환한다.

    5. request의 리디렉션 모드(redirect mode)를 "error"로 설정한다.

    6. Fetch request를 수행하고, 비동기적으로 나머지 단계를 fetch의 processResponse (응답: response)의 일부로서 진행한다.

    7. response의 헤더 리스트에서 MIME 타입을 추출한다. 이 MIME 타입(매개변수는 무시)의 값이 자바스크립트 MIME 타입이 아니라면:

      1. Reject Job Promise를 job과 "SecurityError" DOMException과 함께 호출한다.

      2. 비동기적으로 이 단계를 네트워크 에러로 완료한다.

    8. serviceWorkerAllowed를 가져오기의 결과로 둔다. response의 헤더 목록에서 `Service-Worker-Allowed`를 가져온 결과이다.

      참고: Service-Worker-Allowed 헤더의 정의는 부록 B: 확장 HTTP 헤더를 보라.

    9. serviceWorkerAllowed가 null이 아니면, serviceWorkerAllowed를 동형 디코드의 결과로 설정한다. serviceWorkerAllowed에 대해 수행한다.

    10. policyContainer를 response가 주어진 상태에서 fetch 응답에서 정책 컨테이너 생성하기의 결과로 설정한다.

    11. scopeURL을 registration의 scope url로 둔다.

    12. maxScopeString을 null로 둔다.

    13. serviceWorkerAllowed가 null이면:

      1. resolvedScope를 파싱의 결과로 둔다. "./"을 job의 script url을 기준 URL로 사용하여 파싱한다.

      2. maxScopeString을 "/"와, 그 뒤에 resolvedScope의 경로에 있는 문자열들(빈 문자열 포함)을 서로 "/"로 구분해 이어 붙인 값으로 설정한다.

        참고: resolvedScope의 경로의 마지막 항목은 항상 빈 문자열이므로, maxScopeString은 뒤에 "/"가 붙는다.

    14. 그렇지 않으면:

      1. maxScope를 파싱의 결과로 둔다. serviceWorkerAllowed를 job의 script url을 기준 URL로 사용하여 파싱한다.

      2. maxScope가 실패이면:

        1. 이 단계들을 네트워크 오류로 비동기적으로 완료한다.

      3. maxScope의 출처가 job의 script url의 출처이면:

        1. maxScopeString을 "/"와, 그 뒤에 maxScope의 경로에 있는 문자열들(빈 문자열 포함)을 서로 "/"로 구분해 이어 붙인 값으로 설정한다.

    15. scopeString을 "/"와, 그 뒤에 scopeURL의 경로에 있는 문자열들(빈 문자열 포함)을 서로 "/"로 구분해 이어 붙인 값으로 둔다.

    16. maxScopeString이 null이거나 scopeString이 maxScopeString으로 시작하지 않으면:

      1. Reject Job Promise를 job 및 "SecurityError" DOMException으로 호출한다.

      2. 이 단계들을 네트워크 오류로 비동기적으로 완료한다.

    17. url을 request의 url로 둔다.

    18. updatedResourceMap[url]을 response로 설정한다.

    19. response의 캐시 상태가 "local"이 아니면, registration의 마지막 업데이트 확인 시간을 현재 시각으로 설정한다.

    20. 다음 중 어느 하나라도 참이면 hasUpdatedResources를 true로 설정한다:

    21. hasUpdatedResources가 false이고 newestWorker의 클래식 스크립트 가져오기 플래그가 설정되어 있으면:

      참고: 다음은 주 스크립트가 변경되지 않았으므로 가져온 스크립트가 업데이트되었는지 확인한다.

      1. newestWorker의 스크립트 리소스 맵의 각 importUrl → storedResponse에 대해 순회한다:

        1. importUrl이 url이면 계속한다.

        2. importRequest를 새 요청으로 둔다. 이 요청의 URL은 importUrl이고, 클라이언트는 job의 클라이언트이며, 대상은 "script"이고, 파서 메타데이터는 "not parser-inserted"이며, 요청의 URL 자격 증명 사용 플래그가 설정되어 있다.

        3. 다음 중 어느 하나라도 참이면 importRequest의 캐시 모드를 "no-cache"로 설정한다:

        4. fetchedResponse를 fetching의 결과로 둔다. importRequest에 대해 수행한다.

        5. updatedResourceMap[importRequest의 url]을 fetchedResponse로 설정한다.

        6. fetchedResponse를 fetchedResponse의 unsafe response로 설정한다.

        7. fetchedResponse의 캐시 상태가 "local"이 아니면, registration의 마지막 업데이트 확인 시간을 현재 시각으로 설정한다.

        8. fetchedResponse가 잘못된 가져오기 스크립트 응답이면 계속한다.

          참고: importScripts()에 대한 잘못된 응답은 바이트 단위 확인 목적에서는 무시된다. 현재 작업자에 대한 정상 응답과 잠재적 업데이트 작업자에 대한 정상 응답만 고려된다. 근거 일부는 이슈 #1374를 보라.

        9. fetchedResponse의 본문이 storedResponse의 unsafe response의 본문과 바이트 단위로 동일하지 않으면, hasUpdatedResources를 true로 설정한다.

          참고: 이 단계의 제어는 캐시를 채우기 위해 가져온 모든 스크립트에 대해 계속 진행하도록 루프를 중단하지 않는다.

    22. 비동기적으로 이 단계를 response로 완료한다.

    이 알고리즘이 비동기로 완료되면, 남은 단계들을 script를 비동기 완료 값으로 하여 계속한다.

  8. 만약 script가 null이거나 Is Async Module이 script의 record, script의 base URL, 그리고 « »로 실행되어 true이면:

    1. Reject Job Promise를 job과 TypeError를 인자로 호출한다.

      참고: 이전에 Reject Job Promise가 "SecurityError" DOMException과 함께 호출되었다면 이 단계는 아무것도 하지 않는다.

    2. newestWorker가 null이면 remove registration map[(registration의 storage key, serialized scopeURL)]를 실행한다.

    3. Finish Job을 job에 대해 호출하고 이 단계를 중단한다.

  9. hasUpdatedResources가 false이면:

    1. registration의 update via cache mode를 job의 update via cache mode로 설정한다.

    2. Resolve Job Promise를 job 및 registration을 인자로 호출한다.

    3. Finish Job을 job에 대해 호출하고 이 단계를 중단한다.

  10. worker를 새로운 service worker로 둔다.

  11. worker의 script url을 job의 script url로, worker의 script resource를 script로, worker의 type을 job의 worker type으로, worker의 script resource map을 updatedResourceMap으로 설정한다.

  12. url을 worker의 set of used scripts에 추가한다.

  13. worker의 script resource의 policy container를 policyContainer로 설정한다.

  14. forceBypassCache를 job의 force bypass cache flag가 설정되어 있으면 true, 그렇지 않으면 false로 둔다.

  15. runResult를 Run Service Worker 알고리즘을 worker와 forceBypassCache를 인자로 실행한 결과로 둔다.

  16. runResult가 실패 또는 abrupt completion인 경우:

    1. Reject Job Promise를 job과 TypeError를 인자로 호출한다.

    2. newestWorker가 null이면 remove registration map[(registration의 storage key, serialized scopeURL)]를 실행한다.

    3. Finish Job을 job에 대해 호출한다.

  17. 아니라면, Install 알고리즘을 job, worker, registration을 인자로 실행한다.

소프트 업데이트

사용자 에이전트는 업데이트를 확인하기 위해 원하는 만큼 자주 이 알고리즘을 호출할 수 있습니다.

입력

registration, 서비스 워커 등록

forceBypassCache, 선택적 불리언, 기본값은 false

참고: 구현자는 forceBypassCache를 디버깅(예: 개발자 도구에서 호출)이나 서비스 워커를 확장하는 다른 명세에서 필요에 따라 사용할 수 있습니다.

출력

없음

  1. newestWorker를 최신 워커 가져오기 알고리즘을 registration에 대해 실행한 결과로 둔다.

  2. newestWorker가 null이면 이 단계를 중단한다.

  3. job을 작업 생성을 update, registration의 스토리지 키, registration의 scope url, newestWorker의 script url, null, null로 실행한 결과로 둔다.

  4. job의 워커 타입을 newestWorker의 type으로 설정한다.

  5. forceBypassCache가 true이면 job의 force bypass cache flag를 설정한다.

  6. 작업 스케줄을 job로 호출한다.

소프트 업데이트 요청

이 알고리즘을 사용하면 다른 명세에서 사용자 에이전트가 서비스 워커 등록의 업데이트를 확인하도록 요청할 수 있습니다.

입력

registration, 서비스 워커 등록

requestingStorageKey, 저장소 키

forceBypassCache, 선택적 불리언이며 기본값은 false입니다

출력

없음

  1. registration의 저장소 키가 requestingStorageKey와 같지 않으면 반환합니다.

  2. 사용자 에이전트가 registration에 대한 업데이트 확인 빈도를 제한하기로 결정하면 반환합니다.

    참고: 사용자 에이전트는 업데이트 확인의 빈도를 제한하거나, 서로 가까운 시점에 발생한 registration에 대한 여러 호출을 하나의 호출로 처리하여 과도한 리소스 사용을 방지할 수 있습니다. 호출자는 이 알고리즘의 결과로 업데이트 확인이 이루어진다고 의존해서는 안 됩니다.

  3. registration 및 forceBypassCache를 사용하여 소프트 업데이트 알고리즘을 실행합니다.

참고: 호출하는 명세는 해당 요청과 연결된 저장소 키를 제공할 책임이 있습니다.

설치

입력

job, 작업

worker, 서비스 워커

registration, 서비스 워커 등록

출력

없음

  1. installFailed를 false로 둔다.

  2. newestWorker를 registration을 인수로 전달하여 최신 워커 가져오기 알고리즘을 실행한 결과로 둔다.

  3. registration의 캐시를 통한 업데이트 모드를 job의 캐시를 통한 업데이트 모드로 설정한다.

  4. registration, "installing", worker를 인수로 전달하여 등록 상태 업데이트 알고리즘을 실행한다.

  5. registration의 설치 중인 워커와 "installing"을 인수로 전달하여 워커 상태 업데이트 알고리즘을 실행한다.

  6. 단언: job의 작업 프로미스는 null이 아니다.

  7. job과 registration을 사용하여 작업 프로미스 이행을 호출한다.

  8. settingsObjects를 환경 설정 객체 중 그 출처가 registration의 범위 URL의 출처인 모든 객체로 둔다.

  9. settingsObjects의 각 settingsObject에 대해, settingsObject의 담당 이벤트 루프에서 DOM 조작 태스크 소스를 사용해 다음 단계를 실행하도록 태스크를 큐에 추가한다:

    1. registrationObjects를 settingsObject의 realm에 있는 모든 ServiceWorkerRegistration 객체 중, 그 서비스 워커 등록이 registration인 객체로 둔다.

    2. registrationObjects의 각 registrationObject에 대해, registrationObject에서 updatefound라는 이름의 이벤트를 발생시킨다.

  10. installingWorker를 registration의 설치 중인 워커로 둔다.

  11. installingWorker와 "install"을 사용해 이벤트 건너뛰기 여부 알고리즘을 실행한 결과가 false이면:

    1. job의 강제 캐시 우회 플래그가 설정되어 있으면 forceBypassCache를 true로, 그렇지 않으면 false로 둔다.

    2. installingWorker와 forceBypassCache를 사용해 서비스 워커 실행 알고리즘을 실행한 결과가 실패이면:

      1. installFailed를 true로 설정한다.

    3. 그렇지 않으면:

      1. installingWorker의 이벤트 루프에서 DOM 조작 태스크 소스를 사용하여 다음 단계를 실행하도록 task라는 태스크를 큐에 추가한다:

        1. e를 InstallEvent로 이벤트를 생성한 결과로 둔다.

        2. e의 type 속성을 install로 초기화한다.

        3. installingWorker의 전역 객체에서 e를 디스패치한다.

        4. WaitForAsynchronousExtensions: 다음 하위 단계를 병렬로 실행한다:

          1. e가 더 이상 활성 상태가 아닐 때까지 기다린다.

          2. e의 시간 초과 플래그가 설정되어 있으면, installFailed를 true로 설정한다.

          3. p를 e의 수명 연장 프로미스 모두를 기다리기 위한 프로미스를 가져온 결과로 둔다.

          4. p가 거부되면, installFailed를 true로 설정한다.

        task가 폐기되면, installFailed를 true로 설정한다.

      2. task가 실행되거나 폐기될 때까지 기다린다.

      3. WaitForAsynchronousExtensions라는 레이블이 지정된 단계가 완료될 때까지 기다린다.

  12. installFailed가 true이면:

    1. registration의 설치 중인 워커와 "redundant"를 인수로 전달하여 워커 상태 업데이트 알고리즘을 실행한다.

    2. registration, "installing", null을 인수로 전달하여 등록 상태 업데이트 알고리즘을 실행한다.

    3. newestWorker가 null이면, 등록 맵[(registration의 저장소 키, 직렬화된 registration의 범위 URL)]을 제거한다.

    4. job을 사용하여 작업 완료를 호출하고 이 단계들을 중단한다.

  13. map을 registration의 설치 중인 워커의 스크립트 리소스 맵으로 둔다.

  14. usedSet을 registration의 설치 중인 워커의 사용된 스크립트 집합으로 둔다.

  15. map의 각 url에 대해:

    1. usedSet에 url이 포함되어 있지 않으면, map[url]을 제거한다.

  16. registration의 대기 중인 워커가 null이 아니면:

    1. registration의 대기 중인 워커를 종료한다.

    2. registration의 대기 중인 워커와 "redundant"를 인수로 전달하여 워커 상태 업데이트 알고리즘을 실행한다.

  17. registration, "waiting", registration의 설치 중인 워커를 인수로 전달하여 등록 상태 업데이트 알고리즘을 실행한다.

  18. registration, "installing", null을 인수로 전달하여 등록 상태 업데이트 알고리즘을 실행한다.

  19. registration의 대기 중인 워커와 "installed"를 인수로 전달하여 워커 상태 업데이트 알고리즘을 실행한다.

  20. job을 사용하여 작업 완료를 호출한다.

  21. 이 알고리즘에서 호출된 워커 상태 업데이트가 큐에 추가한 모든 태스크가 실행될 때까지 기다린다.

  22. registration을 사용하여 활성화 시도를 호출한다.

    참고: 여기에서 활성화 시도가 활성화를 트리거하지 않으면, 기존 활성 워커가 제어하는 마지막 클라이언트가 언로드되거나, skipWaiting()이 비동기적으로 호출되거나, 기존 활성 워커의 수명 연장 프로미스가 확정될 때 활성화를 다시 시도한다.

활성화

입력

registration, 서비스 워커 등록

출력

없음

  1. registration의 대기 중인 워커가 null이면, 이 단계들을 중단한다.

  2. registration의 활성 워커가 null이 아니면:

    1. registration의 활성 워커를 종료한다.

    2. registration의 활성 워커와 "redundant"를 인수로 전달하여 워커 상태 업데이트 알고리즘을 실행한다.

  3. registration, "active", registration의 대기 중인 워커를 인수로 전달하여 등록 상태 업데이트 알고리즘을 실행한다.

  4. registration, "waiting", null을 인수로 전달하여 등록 상태 업데이트 알고리즘을 실행한다.

  5. registration의 활성 워커와 "activating"을 인수로 전달하여 워커 상태 업데이트 알고리즘을 실행한다.

    참고: 활성 워커가 활성화 중인 상태가 되면, 런타임 스크립트 오류도 활성 워커의 강제 종료도 활성 워커가 활성화되는 것을 방지하지 못한다.

    참고: 활성화 핸들러는 중요하지 않은 작업(예: 정리)을 수행하도록 설계해야 한다. 이는 특히 활성화 중 브라우저가 종료되는 경우 활성화 핸들러가 모두 완료될 때까지 실행되지 않을 수 있기 때문이다. Service Worker는 활성화 핸들러가 모두 성공적으로 완료되지 않더라도 올바르게 동작하도록 설계해야 한다.

  6. matchedClients를 목록으로 둔다. 이 목록은 서비스 워커 클라이언트 중 그 생성 URL이 registration의 저장소 키와 registration의 범위 URL에 일치하는 것들로 구성된다.

  7. matchedClients의 각 client에 대해, client의 담당 이벤트 루프에서 DOM 조작 태스크 소스를 사용하여 다음 하위 단계를 실행하도록 태스크를 큐에 추가한다:

    1. readyPromise를 client의 전역 객체의 ServiceWorkerContainer 객체의 ready 프로미스로 둔다.

    2. readyPromise가 null이면, 계속한다.

    3. readyPromise가 대기 중이면, readyPromise의 관련 설정 객체에서 registration을 나타내는 서비스 워커 등록 객체를 가져온 결과로 readyPromise를 이행한다.

  8. registration을 사용하는 각 서비스 워커 클라이언트 client에 대해:

    1. client의 활성 워커를 registration의 활성 워커로 설정한다.

    2. client를 인수로 사용하여 컨트롤러 변경 알림 알고리즘을 호출한다.

  9. activeWorker를 registration의 활성 워커로 둔다.

  10. activeWorker와 "activate"를 사용하여 이벤트 건너뛰기 여부 알고리즘을 실행한 결과가 false이면:

    1. activeWorker를 사용하여 서비스 워커 실행 알고리즘을 실행한 결과가 실패가 아니면:

      1. activeWorker의 이벤트 루프에서 DOM 조작 태스크 소스를 사용하여 다음 단계를 실행하도록 task라는 태스크를 큐에 추가한다:

        1. e를 ExtendableEvent로 이벤트를 생성한 결과로 둔다.

        2. e의 type 속성을 activate로 초기화한다.

        3. activeWorker의 전역 객체에서 e를 디스패치한다.

        4. WaitForAsynchronousExtensions: e가 더 이상 활성 상태가 아닐 때까지 병렬로 기다린다.

      2. task가 실행되거나 폐기될 때까지 기다린다.

      3. WaitForAsynchronousExtensions라는 레이블이 지정된 단계가 완료될 때까지 기다린다.

  11. registration의 활성 워커와 "activated"를 인수로 전달하여 워커 상태 업데이트 알고리즘을 실행한다.

활성화 시도

입력

registration, 서비스 워커 등록

출력

없음

  1. registration의 대기 중인 워커가 null이면 반환한다.

  2. registration의 활성 워커가 null이 아니면서, registration의 활성 워커의 state가 "activating"이면 반환한다.

    참고: 기존 활성 워커가 activating 상태라면, 대기 중인 워커의 활성화가 지연된다.

  3. 다음 중 하나라도 참이면 활성화를 registration로 호출한다:

ServiceWorkerGlobalScope 설정

입력

serviceWorker, 서비스 워커

출력

ServiceWorkerGlobalScope 객체 또는 null

참고: 이 알고리즘은 CSP 검사 등에 사용할 수 있는 ServiceWorkerGlobalScope를 반환하거나 null을 반환한다. serviceWorker에 활성 ServiceWorkerGlobalScope가 있으면 반환하고, 아니면 새로 생성한다.

이 알고리즘은 CSP, COEP와 같은 보안 검사를 위해 필요 최소한의 서비스 워커 셋업만 수행합니다. 본 명세는 이러한 검사가 실행되기 전에 반드시 이 알고리즘이 호출될 것을 보장합니다.

명세에서 이러한 보안 검사는 ServiceWorkerGlobalScope, relevant settings object, realm, agent의 생성을 요구합니다. 실제 구현에서는 해야 할 작업이 훨씬 적을 수 있습니다. 따라서 구현에서는 이 알고리즘과 등가인 부분에서 적은 작업만 처리하고, Run Service Worker에서 더 많은 작업을 할 수도 있습니다. 단, 결과가 밖에서 볼 때 동일하다면 허용됩니다. (특히 보안 검사 결과가 동일하다면 문제없습니다.)

  1. unsafeCreationTime을 공유 비안전 현재 시간(unsafe shared current time)으로 둔다.

  2. 만약 serviceWorker가 실행중(running)이라면, serviceWorker의 global object를 반환한다.

  3. serviceWorker의 state가 "redundant"라면 null을 반환한다.

  4. 만약 serviceWorker의 global object가 null이 아니라면, serviceWorker의 global object를 반환한다.

  5. 명제: serviceWorker의 start status는 null이다.

  6. setupFailed를 false로 둔다.

  7. globalObject를 null로 둔다.

  8. agent를 서비스 워커 에이전트 획득의 결과로 두고, 그 컨텍스트에서 다음 단계를 실행한다:

    1. realmExecutionContext를 새로운 realm 생성을 agent와 아래 커스터마이즈를 인자로 실행한 결과로 둔다:

      • 글로벌 객체(global object)로 새로운 ServiceWorkerGlobalScope 객체를 생성한다. 생성한 객체를 workerGlobalScope로 둔다.

    2. settingsObject를 다음 알고리즘이 정의된 새로운 environment settings object로 둔다:

      Realm 실행 컨텍스트

      realmExecutionContext를 반환한다.

      모듈 맵

      workerGlobalScope의 모듈 맵을 반환한다.

      API 기준 URL

      serviceWorker의 스크립트 URL을 반환한다.

      출처

      이를 등록한 서비스 워커 클라이언트의 출처를 반환한다.

      교차 사이트 조상 존재 여부

      이를 등록한 서비스 워커 클라이언트의 교차 사이트 조상 존재 여부를 반환한다.

      정책 컨테이너

      workerGlobalScope의 정책 컨테이너를 반환한다.

      시간 원점

      workerGlobalScope의 교차 출처 격리 기능이 주어졌을 때 unsafeCreationTime을 정밀도를 낮춘 결과를 반환한다.

    3. settingsObject의 ID를 새로운 고유 불투명 문자열로, 생성 URL을 serviceWorker의 스크립트 URL로, 최상위 생성 URL을 null로, 최상위 출처를 구현 정의 값으로, 대상 브라우징 컨텍스트를 null로, 그리고 활성 서비스 워커를 null로 설정한다.

    4. workerGlobalScope의 url을 serviceWorker의 script url로 설정한다.

    5. workerGlobalScope의 policy container를 serviceWorker의 script resource의 policy container로 설정한다.

    6. workerGlobalScope의 type을 serviceWorker의 type으로 설정한다.

    7. 새 WorkerLocation 객체를 생성하여 workerGlobalScope와 연결한다.

    8. 전역 객체의 CSP 초기화 알고리즘을 workerGlobalScope에 실행하여 "Blocked"를 반환하면 setupFailed를 true로 하고 이 단계를 중단한다.

    9. globalObject를 workerGlobalScope로 설정한다.

  9. globalObject가 null이 아니거나, setupFailed가 true가 될 때까지 기다린다.

  10. 만약 setupFailed가 true라면 null을 반환한다.

  11. globalObject를 반환한다.

서비스 워커 실행

입력

serviceWorker, 서비스 워커

forceBypassCache, 선택적 불리언, 기본값은 false

출력

Completion 또는 실패

참고: 이 알고리즘은 서비스 워커가 실행 중이 되거나 시작에 실패할 때까지 블록됩니다.

  1. serviceWorker가 실행 중이면, serviceWorker의 시작 상태를 반환한다.

  2. serviceWorker의 상태가 "redundant"이면, 실패를 반환한다.

  3. 단언: serviceWorker의 시작 상태는 null이다.

  4. script를 serviceWorker의 스크립트 리소스로 둔다.

  5. 단언: script는 null이 아니다.

  6. startFailed를 false로 둔다.

  7. workerGlobalScope를 serviceWorker의 전역 객체로 둔다.

  8. workerGlobalScope가 null이면:

    1. workerGlobalScope를 serviceWorker를 사용하여 ServiceWorkerGlobalScope 설정 알고리즘을 실행한 결과로 설정한다.

    2. workerGlobalScope가 null이면, 실패를 반환한다.

    3. serviceWorker의 전역 객체를 workerGlobalScope로 설정한다.

  9. workerGlobalScope의 Realm 실행 컨텍스트에 대한 에이전트를 얻고, 해당 컨텍스트에서 다음 단계를 실행한다.

    1. forceBypassCache가 true이면 workerGlobalScope의 가져오기 스크립트에 대한 강제 캐시 우회 플래그를 설정한다.

    2. serviceWorker가 활성 워커이고, serviceWorker의 포함 서비스 워커 등록의 태스크 큐에 큐에 들어간 태스크가 있으면, 원래의 태스크 소스를 사용하여 동일한 순서로 serviceWorker의 이벤트 루프의 태스크 큐에 그것들을 큐에 넣는다.

    3. evaluationStatus를 null로 둔다.

    4. script가 클래식 스크립트이면:

      1. evaluationStatus를 script 클래식 스크립트를 실행한 결과로 설정한다.

      2. evaluationStatus.[[Value]]가 비어 있으면, 이는 스크립트가 평가되지 않았음을 의미한다. startFailed를 true로 설정하고 이 단계를 중단한다.

    5. 그렇지 않고 script가 모듈 스크립트이면:

      1. evaluationPromise를 오류 보고를 false로 설정하여 script 모듈 스크립트를 실행한 결과로 둔다.

      2. 단언: evaluationPromise.[[PromiseState]]는 "pending"이 아니다.

      3. evaluationPromise.[[PromiseState]]가 "rejected"이면:

        1. evaluationStatus를 ThrowCompletion(evaluationPromise.[[PromiseResult]])으로 설정한다.

      4. 그렇지 않으면:

        1. evaluationStatus를 NormalCompletion(undefined)으로 설정한다.

    6. 스크립트가 서비스 워커 종료 알고리즘에 의해 중단된 경우, startFailed를 true로 설정하고 이 단계를 중단한다.

    7. serviceWorker의 시작 상태를 evaluationStatus로 설정한다.

    8. script의 평가된 적 있음 플래그가 설정되어 있지 않으면:

      1. settingsObject의 전역 객체와 연결된 이벤트 리스너 리스트의 이벤트 유형 각각의 eventType에 대해:

        1. eventType을 workerGlobalScope와 연결된 서비스 워커의 처리할 이벤트 유형 집합에 추가한다.

        참고: 전역 객체와 연결된 이벤트 리스너 리스트에 현재 추가된 이벤트 리스너가 하나도 없으면, 서비스 워커의 처리할 이벤트 유형 집합은 빈 집합으로 유지된다.

      2. script의 평가된 적 있음 플래그를 설정한다.

      3. serviceWorker의 모든 가져오기 리스너가 비어 있음 플래그를 해제한다.

      4. 사용자 에이전트는 workerGlobalScope를 사용한 모든 가져오기 리스너가 비어 있음 알고리즘이 true를 반환하는 경우, serviceWorker의 모든 가져오기 리스너가 비어 있음 플래그를 설정할 수 있다.

    9. settingsObject이 지정한 담당 이벤트 루프가 파괴될 때까지 실행한다.

    10. workerGlobalScope의 활성 타이머 맵을 비운다.

  10. serviceWorker가 실행 중이 되거나 startFailed가 true가 될 때까지 기다린다.

  11. startFailed가 true이면, 실패를 반환한다.

  12. serviceWorker의 시작 상태를 반환한다.

모든 fetch 리스너 비어 있음

입력

workerGlobalScope, 글로벌 객체

출력

불리언 값

  1. workerGlobalScope의 처리할 이벤트 타입 집합이 fetch를 포함하지 않으면 true를 반환한다.

  2. eventHandler를 workerGlobalScope의 event handler map["onfetch"] 값으로 둔다.

  3. eventListenerCallbacks를 legacy-obtain service worker fetch event listener callbacks를 workerGlobalScope에 대해 실행한 결과로 둔다.

  4. 각 eventListenerCallback을 eventListenerCallbacks에서 반복하여:

    1. callback을 null로 둔다.

    2. 만약 eventHandler가 null이 아니고 eventListenerCallback이 eventHandler의 listener의 callback과 같다면, callback을 ECMAScript 값으로 변환한 eventHandler의 value 결과로 설정한다.

    3. 그 외에는, callback을 ECMAScript 값으로 변환한 eventListenerCallback의 결과로 설정한다.

    4. 만약 IsCallable(callback)이 false라면 false를 반환한다.

      참고: Callback 객체가 handleEvent(event) 형식을 사용할 경우 비어 있지 않은 것으로 간주한다. 이는 체크 도중 handleEvent(event) getter를 호출하여 리스너가 변경되는 것을 방지한다.

    5. 만약 callback의 function body가 비어 있지 않다면(즉, statement 또는 declaration이 존재할 경우), false를 반환한다.

    참고: 이는 () => {}와 같은 빈 fetch 리스너를 탐지한다. 어떤 사이트들은 fetch 이벤트 리스너에 빈 본문을 추가하여 Chromium에서 PWA로 인식시키기도 한다.

  5. true를 반환한다.

참고: 사용자 에이전트는 불필요한 빈 "fetch" 리스너가 있을 때 경고를 표시하고, 성능에 악영향을 줄 수 있음을 안내할 수 있다.

서비스 워커 종료

입력

serviceWorker, 서비스 워커

출력

없음

  1. serviceWorker의 메인 루프와 병렬로 다음 단계를 실행한다.

    1. serviceWorkerGlobalScope를 serviceWorker의 전역 객체로 둔다.

    2. serviceWorkerGlobalScope의 닫는 중 플래그를 true로 설정한다.

    3. serviceWorker의 연장된 이벤트 집합에서 모든 항목을 제거한다.

    4. serviceWorkerGlobalScope의 이벤트 루프의 태스크 큐에 큐에 들어간 태스크 중, 태스크 소스가 가져오기 처리 태스크 소스 또는 기능 이벤트 처리 태스크 소스인 것이 있으면, 원래의 태스크 소스를 사용하여 동일한 순서로 serviceWorker의 포함 서비스 워커 등록의 해당 태스크 큐에 그것들을 큐에 넣고, serviceWorkerGlobalScope의 이벤트 루프의 태스크 큐에서 모든 태스크(태스크 소스가 가져오기 처리 태스크 소스도 기능 이벤트 처리 태스크 소스도 아닌 태스크 포함)를 처리하지 않고 폐기한다.

      참고: 이는 사실상 가져오기 이벤트와 푸시 이벤트 같은 기타 기능 이벤트는 등록의 태스크 큐에 백업되는 반면, 메시지 이벤트를 포함한 기타 태스크는 폐기됨을 의미한다.

    5. serviceWorker에서 현재 실행 중인 스크립트를 중단한다.

    6. serviceWorker의 시작 상태를 null로 설정한다.

Fetch 처리

Fetch 처리 알고리즘은 fetch 처리를 서비스 워커 컨텍스트에 전달하는 진입점입니다.

입력

request, 요청

fetchController, 가져오기 컨트롤러

useHighResPerformanceTimers, 불리언

출력

응답 또는 서비스 워커 타이밍 정보

  1. registration을 null로 둔다.

  2. client를 request의 클라이언트로 둔다.

  3. reservedClient를 request의 예약된 클라이언트로 둔다.

  4. preloadResponse를 새로운 프로미스로 둔다.

  5. workerRealm을 null로 둔다.

  6. timingInfo를 새로운 서비스 워커 타이밍 정보로 둔다.

  7. 단언: request의 대상은 "serviceworker"가 아니다.

  8. request의 대상이 "embed" 또는 "object"이면:

    1. null을 반환한다.

  9. 그렇지 않고 request가 비하위 리소스 요청이면:

    1. reservedClient가 null이 아니며 환경 설정 객체이면:

      1. reservedClient가 보안 컨텍스트가 아니면, null을 반환한다.

    2. 그렇지 않으면:

      1. request의 URL이 잠재적으로 신뢰할 수 있는 URL이 아니면, null을 반환한다.

    3. request가 탐색 요청이고 이를 트리거한 탐색이 shift+reload 또는 이에 상응하는 동작으로 시작되었으면, null을 반환한다.

    4. reservedClient가 null이 아님을 단언한다.

    5. storage key를 reservedClient가 주어졌을 때 스토리지 키를 얻는 알고리즘을 실행한 결과로 둔다.

    6. registration을 storage key와 request의 URL이 주어졌을 때 서비스 워커 등록 일치시키기를 실행한 결과로 설정한다.

    7. registration이 null이거나 registration의 활성 워커가 null이면, null을 반환한다.

    8. request의 대상이 "report"가 아니면, reservedClient의 활성 서비스 워커를 registration의 활성 워커로 설정한다.

    참고: 이 시점부터 서비스 워커 클라이언트는 자신의 활성 서비스 워커의 포함 서비스 워커 등록을 사용하기 시작한다.

  10. 그렇지 않고 request가 하위 리소스 요청이면:

    1. client의 활성 서비스 워커가 null이 아니면, registration을 client의 활성 서비스 워커의 포함 서비스 워커 등록으로 설정한다.

    2. 그렇지 않으면, null을 반환한다.

  11. activeWorker를 registration의 활성 워커로 둔다.

  12. 다음 중 하나라도 true이면 shouldSoftUpdate를 true로, 그렇지 않으면 false로 둔다.

  13. activeWorker의 라우터 규칙 리스트가 비어 있지 않으면:

    1. timingInfo의 워커 라우터 평가 시작을 useHighResPerformanceTimers가 주어졌을 때의 정밀도가 낮아진 공유 현재 시간으로 설정한다.

    2. source를 registration의 활성 워커와 request를 사용하여 라우터 소스 가져오기 알고리즘을 실행한 결과로 둔다.

    3. source가 null이 아니면:

      1. timingInfo의 워커와 일치한 라우터 소스를 source로 설정하고, 워커 최종 라우터 소스를 "network"로 설정한다.

      2. source가 "network"이면:

        1. shouldSoftUpdate가 true이면, registration을 사용하여 소프트 업데이트 알고리즘을 병렬로 실행한다.

        2. timingInfo를 반환한다.

      3. 그렇지 않고 source가 "cache"이거나, source["cacheName"]이 존재하면:

        1. shouldSoftUpdate가 true이면, registration을 사용하여 소프트 업데이트 알고리즘을 병렬로 실행한다.

        2. timingInfo의 워커 캐시 조회 시작을 useHighResPerformanceTimers가 주어졌을 때의 정밀도가 낮아진 공유 현재 시간으로 설정한다.

        3. environment를 null로 둔다.

        4. request가 비하위 리소스 요청이면:

          1. environment를 reservedClient로 설정한다.

        5. 그렇지 않으면:

          1. environment를 client로 설정한다.

        6. caches를 environment와 "caches"를 사용하여 로컬 스토리지 보틀 맵을 얻는 알고리즘을 실행한 결과로 둔다.

        7. caches의 각 cacheName → cache에 대해 반복한다.

          1. source["cacheName"]이 존재하고 source["cacheName"]이 cacheName이 아니면, 계속한다.

          2. requestResponses를 request, 새로운 CacheQueryOptions, 그리고 cache를 사용하여 캐시 조회를 실행한 결과로 둔다.

          3. requestResponses가 빈 리스트이면, timingInfo를 반환한다.

          4. 그렇지 않으면:

            1. requestResponse를 requestResponses의 첫 번째 요소로 둔다.

            2. response를 requestResponse의 응답으로 둔다.

            3. globalObject를 activeWorker의 전역 객체로 둔다.

            4. globalObject가 null이면:

              1. globalObject를 activeWorker를 사용하여 ServiceWorkerGlobalScope 설정을 실행한 결과로 설정한다.

            5. globalObject가 null이면, timingInfo를 반환한다.

              참고: 이는 CORS 검사에 필요하기 때문에 ServiceWorkerGlobalScope만 생성한다. 구현이 실제로 여기서 ServiceWorkerGlobalScope를 생성할 것으로 예상되지는 않는다.

            6. response의 유형이 "opaque"이고, globalObject의 출처, globalObject, "", 그리고 response의 내부 응답을 사용한 교차 출처 리소스 정책 검사가 blocked를 반환하면, timingInfo를 반환한다.

            7. timingInfo의 워커 최종 라우터 소스를 "cache"로 설정한다.

            8. result의 서비스 워커 타이밍 정보를 timingInfo로 설정한다.

            9. response를 반환한다.

        8. timingInfo를 반환한다.

      4. 그렇지 않고 source가 "race-network-and-fetch-handler"이고, request의 메서드가 `GET`이면:

        1. shouldSoftUpdate가 true이면, registration을 사용하여 소프트 업데이트 알고리즘을 병렬로 실행한다.

        2. queue를 경쟁 결과의 빈 큐로 둔다.

        3. raceFetchController를 null로 둔다.

        4. raceResponse를 값이 "pending"인 경쟁 응답으로 둔다.

        5. 다음 하위 단계를 병렬로 실행한다.

          1. fetchController의 상태가 "terminated" 또는 "aborted"이면, raceResponse를 값이 null인 경쟁 응답으로 설정하고 이 단계를 중단한다.

          2. raceFetchController를 request가 주어졌을 때 가져오기를 호출한 결과로 설정하되, processResponse는 응답 raceNetworkRequestResponse가 주어졌을 때 다음 단계로 설정한다.

            1. 다음 단계를 실행하되, fetchController의 상태가 "terminated" 또는 "aborted"이면 중단한다.

              1. raceResponse의 값을 raceNetworkRequestResponse로 설정한다.

              2. raceNetworkRequestResponse의 상태가 정상 상태이면:

                1. raceNetworkResult를 라우팅된 응답이 raceNetworkRequestResponse이고 사용된 경로가 "network"인 경쟁 결과로 둔다.

                2. raceNetworkResult를 queue에 큐에 넣는다.

            2. 중단되었고 raceFetchController가 null이 아니면:

              1. raceFetchController를 중단한다.

              2. raceResponse를 값이 null인 경쟁 응답으로 설정한다.

        6. preloadResponse를 undefined로 이행한다.

        7. 다음 하위 단계를 병렬로 실행한다.

          1. fetchHandlerResponse를 request, registration, useHighResPerformanceTimers, timingInfo, workerRealm, reservedClient, preloadResponse 및 raceResponse를 사용하여 가져오기 이벤트 생성 및 디스패치를 실행한 결과로 둔다.

          2. fetchHandlerResponse가 null이 아니고 네트워크 오류도 아니며, raceFetchController가 null이 아니면, raceFetchController를 중단한다.

          3. raceFetchHandlerResult를 라우팅된 응답이 fetchHandlerResponse이고 사용된 경로가 "fetch-event"인 경쟁 결과로 둔다.

          4. raceFetchHandlerResult를 queue에 큐에 넣는다.

        8. queue가 비어 있지 않을 때까지 기다린다.

        9. result를 queue에서 큐에서 꺼낸 결과로 둔다.

        10. routedResponse를 result의 라우팅된 응답으로 둔다.

        11. routedResponse가 null이면:

          1. timingInfo를 반환한다.

        12. result의 사용된 경로가 "network"이면:

          1. routedResponse의 서비스 워커 타이밍 정보를 timingInfo로 설정한다.

        13. routedResponse의 서비스 워커 타이밍 정보의 워커 최종 라우터 소스를 result의 사용된 경로로 설정한다.

        14. routedResponse를 반환한다.

      5. 단언: source는 "fetch-event"이다.

  14. responseForAutoPreload를 null로 둔다.

  15. request가 탐색 요청이고, request의 메서드가 `GET`이며, registration의 활성 워커의 처리할 이벤트 유형 집합에 fetch가 포함되어 있고, registration의 활성 워커의 모든 가져오기 리스너가 비어 있음 플래그가 설정되어 있지 않으면:

    1. registration의 탐색 미리 로드 활성화 플래그가 설정되어 있으면:

      참고: 위 조건 중 registration의 활성 워커의 처리할 이벤트 유형 집합에 fetch가 포함되지 않는다는 점만 제외하고 모두 true이면, 개발자의 의도가 명확하지 않으므로 사용자 에이전트는 콘솔 경고를 표시할 수 있다.

      1. preloadRequest를 요청 request를 복제한 결과로 둔다.

      2. preloadRequestHeaders를 preloadRequest의 헤더 리스트로 둔다.

      3. preloadResponseObject를 가드가 "immutable"인 새로운 Headers 객체와 연결된 새로운 Response 객체로 둔다.

      4. preloadRequestHeaders에 이름이 `Service-Worker-Navigation-Preload`이고 값이 registration의 탐색 미리 로드 헤더 값인 새로운 헤더를 추가한다.

      5. preloadRequest의 서비스 워커 모드를 "none"으로 설정한다.

      6. preloadFetchController를 null로 둔다.

      7. 다음 하위 단계를 병렬로 실행하되, fetchController의 상태가 "terminated" 또는 "aborted"이면 중단한다.

        1. preloadFetchController를 preloadRequest를 가져온 결과로 설정한다.

          navigationPreloadResponse에 대한 processResponse로서 다음 하위 단계를 실행한다.

          1. navigationPreloadResponse의 유형이 "error"이면, preloadResponse를 TypeError로 거부하고 이 하위 단계를 종료한다.

          2. preloadResponseObject를 navigationPreloadResponse와 연결한다.

          3. preloadResponse를 preloadResponseObject로 이행한다.

      8. 중단되었으면:

        1. deserializedError를 null과 workerRealm이 주어졌을 때 직렬화된 중단 이유를 역직렬화한 결과로 둔다.

        2. deserializedError를 사용하여 preloadFetchController를 중단한다.

    2. 그렇지 않고 timingInfo의 워커와 일치한 라우터 소스가 "fetch-event"가 아니면, 사용자 에이전트는 다음 하위 단계를 실행할 수 있다.

      참고: 사용자 에이전트는 부트스트랩 비용을 최소화하기 위해 가져오기 이벤트를 생성하는 작업과 병렬로 네트워크 요청을 추측적으로 디스패치할 수 있다.

      1. 단언: timingInfo의 워커와 일치한 라우터 소스는 null이다.

      2. autoPreloadFetchController를 null로 둔다.

      3. responseForAutoPreload를 값이 "pending"인 경쟁 응답으로 설정한다.

      4. 다음 하위 단계를 병렬로 실행하되, fetchController의 상태가 "terminated" 또는 "aborted"이면 중단한다.

        1. autoPreloadFetchController를 request가 주어졌을 때 가져오기를 호출한 결과로 설정하되, processResponse는 응답 autoPreloadRequestResponse가 주어졌을 때 다음 단계로 설정한다.

          1. responseForAutoPreload의 값을 autoPreloadRequestResponse로 설정한다.

      5. 중단되었고 autoPreloadFetchController가 null이 아니면:

        1. autoPreloadFetchController를 중단한다.

        2. responseForAutoPreload를 값이 null인 경쟁 응답으로 설정한다.

      6. preloadResponse를 undefined로 이행한다.

  16. 그렇지 않으면, preloadResponse를 undefined로 이행한다.

  17. fetchResult를 request, registration, useHighResPerformanceTimers, timingInfo, workerRealm, reservedClient, preloadResponse 및 responseForAutoPreload를 사용하여 가져오기 이벤트 생성 및 디스패치를 실행한 결과로 둔다.

  18. timingInfo의 워커 최종 라우터 소스가 빈 문자열이 아니면:

    1. timingInfo의 워커 최종 라우터 소스가 "network"임을 단언한다.

    2. fetchResult가 null이면, timingInfo를 반환한다.

    3. 그렇지 않으면:

      1. fetchResult의 서비스 워커 타이밍 정보의 워커 최종 라우터 소스가 "network"임을 단언한다.

      2. fetchResult의 서비스 워커 타이밍 정보의 워커 최종 라우터 소스를 "fetch-event"로 설정한다.

  19. fetchResult를 반환한다.

Fetch 이벤트 생성 및 디스패치

입력

request, 요청

registration, 서비스 워커 등록

useHighResPerformanceTimers, 불리언

timingInfo, 서비스 워커 타이밍 정보

workerRealm, 전역 객체의 관련 Realm

reservedClient, 예약된 클라이언트

preloadResponse, 프로미스

raceResponse, 경쟁 응답 또는 null

출력

응답 또는 null

  1. response를 null로 둔다.

  2. eventCanceled를 false로 둔다.

  3. client를 request의 클라이언트로 둔다.

  4. activeWorker를 registration의 활성 워커로 둔다.

  5. eventHandled를 null로 둔다.

  6. handleFetchFailed를 false로 둔다.

  7. respondWithEntered를 false로 둔다.

  8. networkError를 네트워크 오류로 둔다.

  9. raceResponse가 null이 아니면:

    1. networkError의 서비스 워커 타이밍 정보를 timingInfo로 설정한다.

  10. 다음 중 하나라도 true이면 shouldSoftUpdate를 true로, 그렇지 않으면 false로 둔다.

  11. "fetch"와 activeWorker를 사용하여 이벤트를 건너뛰어야 하는지 판단 알고리즘을 실행한 결과가 true이면:

    1. shouldSoftUpdate가 true이면, registration을 사용하여 소프트 업데이트 알고리즘을 병렬로 실행한다.

    2. null을 반환한다.

  12. activeWorker의 모든 가져오기 리스너가 비어 있음 플래그가 설정되어 있으면:

    1. 병렬로:

      1. activeWorker의 상태가 "activating"이면, activeWorker의 상태가 "activated"가 될 때까지 기다린다.

      2. activeWorker를 사용하여 서비스 워커 실행 알고리즘을 실행한다.

      3. shouldSoftUpdate가 true이면, registration을 사용하여 소프트 업데이트 알고리즘을 실행한다.

    2. null을 반환한다.

  13. useHighResPerformanceTimers가 true이면, useHighResPerformanceTimers를 activeWorker의 전역 객체의 교차 출처 격리 기능으로 설정한다.

  14. timingInfo의 시작 시간을 useHighResPerformanceTimers가 주어졌을 때의 정밀도가 낮아진 공유 현재 시간으로 둔다.

  15. activeWorker의 상태가 "activating"이면, activeWorker의 상태가 "activated"가 될 때까지 기다린다.

  16. activeWorker를 사용하여 서비스 워커 실행 알고리즘을 실행한 결과가 실패이면, handleFetchFailed를 true로 설정한다.

  17. 그렇지 않으면:

    1. workerRealm을 activeWorker의 전역 객체의 관련 Realm으로 설정한다.

    2. eventHandled를 workerRealm의 새 프로미스로 설정한다.

    3. raceResponse가 null이 아니면, activeWorker의 전역 객체의 경쟁 응답 맵[request]을 raceResponse로 설정한다.

    4. 다음 하위 단계를 실행하는 task 태스크를 큐에 넣는다.

      1. e를 FetchEvent로 이벤트를 생성한 결과로 둔다.

      2. abortController를 workerRealm을 사용하는 새 AbortController 객체로 둔다.

      3. requestObject를 request, 가드가 "immutable"인 새 Headers 객체, abortController의 신호, 그리고 workerRealm이 주어졌을 때 Request 객체를 생성한 결과로 둔다.

      4. e의 type 속성을 fetch로 초기화한다.

      5. e의 cancelable 속성을 true로 초기화한다.

      6. e의 request 속성을 requestObject로 초기화한다.

      7. e의 preloadResponse를 preloadResponse로 초기화한다.

      8. client가 null이 아니면, e의 clientId 속성을 client의 ID로 초기화한다.

      9. request가 비하위 리소스 요청이고, request의 대상이 "report"가 아니며, reservedClient가 null이 아니면, e의 resultingClientId 속성을 reservedClient의 ID로 초기화한다.

      10. request가 탐색 요청이면, e의 replacesClientId 속성을 request의 대체하는 클라이언트 ID로 초기화한다.

      11. e의 handled를 eventHandled로 초기화한다.

      12. timingInfo의 가져오기 이벤트 디스패치 시간을 useHighResPerformanceTimers가 주어졌을 때의 정밀도가 낮아진 공유 현재 시간으로 둔다.

      13. activeWorker의 전역 객체에서 e를 디스패치한다.

      14. activeWorker와 e를 사용하여 서비스 워커 연장 이벤트 집합 업데이트를 호출한다.

      15. e의 respond-with 진입 플래그가 설정되어 있으면, respondWithEntered를 true로 설정한다.

      16. e의 응답 대기 플래그가 설정되어 있으면:

        1. e의 응답 대기 플래그가 해제될 때까지 기다린다.

        2. e의 respond-with 오류 플래그가 설정되어 있으면, handleFetchFailed를 true로 설정한다.

        3. 그렇지 않으면, response를 e의 잠재적 응답으로 설정한다.

      17. response가 null이고, request의 본문이 null이 아니며, request의 본문의 소스가 null이면:

        1. request의 본문을 사용할 수 없으면, handleFetchFailed를 true로 설정한다.

        2. 그렇지 않으면, undefined를 사용하여 request의 본문을 취소한다.

      18. response가 null이 아니면, response의 서비스 워커 타이밍 정보를 timingInfo로 설정한다.

      19. e의 취소됨 플래그가 설정되어 있으면, eventCanceled를 true로 설정한다.

      20. fetchController의 상태가 "terminated" 또는 "aborted"이면:

        1. deserializedError를 fetchController의 직렬화된 중단 이유와 workerRealm이 주어졌을 때 직렬화된 중단 이유를 역직렬화한 결과로 둔다.

        2. deserializedError를 사용하여 abortController에서 중단을 신호하도록 태스크를 큐에 넣는다.

      task가 폐기되면, handleFetchFailed를 true로 설정한다.

      task는 activeWorker의 이벤트 루프와 가져오기 처리 태스크 소스를 사용해야 한다.

  18. task가 실행되거나 handleFetchFailed가 true가 될 때까지 기다린다.

  19. shouldSoftUpdate가 true이면, registration을 사용하여 소프트 업데이트 알고리즘을 병렬로 실행한다.

  20. activeWorker의 전역 객체의 경쟁 응답 맵[request]이 존재하면, activeWorker의 전역 객체의 경쟁 응답 맵[request]을 제거한다.

  21. respondWithEntered가 false이면:

    1. eventCanceled가 true이면:

      1. eventHandled가 null이 아니면, workerRealm에서 "NetworkError" DOMException으로 eventHandled를 거부한다.

      2. networkError를 반환한다.

    2. eventHandled가 null이 아니면, eventHandled를 이행한다.

    3. raceResponse가 null이 아니고, raceResponse의 값이 null이 아니면:

      1. raceResponse의 값이 "pending"이 아닐 때까지 기다린다.

      2. raceResponse의 값이 응답이면, raceResponse의 값을 반환한다.

    4. null을 반환한다.

  22. handleFetchFailed가 true이면:

    1. eventHandled가 null이 아니면, workerRealm에서 "NetworkError" DOMException으로 eventHandled를 거부한다.

    2. networkError를 반환한다.

  23. eventHandled가 null이 아니면, eventHandled를 이행한다.

  24. response를 반환한다.

URL 패턴 파싱

입력

rawPattern, URLPatternCompatible

serviceWorker, 서비스 워커

출력

URL 패턴

  1. baseURL을 serviceWorker의 스크립트 URL로 둔다.

  2. rawPattern과 baseURL을 인자로 하여 Web IDL 값으로부터 URL 패턴 생성 알고리즘을 실행한 결과를 반환한다.

라우터 조건 검증

입력

condition, RouterCondition

serviceWorker, 서비스 워커

출력

불리언 값

  1. hasCondition을 false로 둔다.

  2. condition["urlPattern"] 존재하면:

    1. rawPattern을 condition["urlPattern"]로 둔다.

    2. pattern을 URL 패턴 파싱 알고리즘을 rawPattern, serviceWorker로 실행한 결과로 둔다. 만약 예외가 발생하면 false를 반환한다.

    3. pattern이 정규식 그룹을 포함하면 false를 반환한다.

      참고: 사용자 정의 정규식을 실행하는 것은 보안상 문제이므로 금지된다.

    4. hasCondition을 true로 설정한다.

  3. condition["requestMethod"] 존재하면:

    1. method을 condition["requestMethod"]로 둔다.

    2. method가 method가 아니면 false를 반환한다.

    3. method가 금지된 method이면 false를 반환한다.

    4. hasCondition을 true로 설정한다.

  4. condition["requestMode"] 존재하면 hasCondition을 true로 설정한다.

  5. condition["requestDestination"] 존재하면 hasCondition을 true로 설정한다.

  6. condition["runningStatus"] 존재하면 hasCondition을 true로 설정한다.

  7. condition["_or"] 존재하면:

    1. hasCondition이 true면 false를 반환한다.

      참고: 라우터 규칙의 이해를 쉽게 하기 위해 "or" 조건은 다른 조건과 상호 배타적이다.

    2. orConditions를 condition["_or"]로 둔다.

    3. orConditions의 각 orCondition에 대해:

      1. 라우터 조건 검증 알고리즘을 orCondition, serviceWorker로 실행한 결과가 false면 false를 반환한다.

    4. hasCondition을 true로 설정한다.

  8. condition["not"] 존재하면:

    1. hasCondition이 true면 false를 반환한다.

      참고: 라우터 규칙의 이해를 쉽게 하기 위해 "not" 조건은 다른 조건과 상호 배타적이다.

    2. 라우터 조건 검증 알고리즘을 condition["not"], serviceWorker로 실행한 결과가 false면 false를 반환한다.

    3. hasCondition을 true로 설정한다.

  9. hasCondition을 반환한다.

라우터 조건 매칭

입력

condition, RouterCondition

serviceWorker, 서비스 워커

request, request

출력

불리언 값

참고: 여러 조건(e.g. urlPattern, runningStatus, requestMethod 등이 설정된 경우), 모든 조건이 일치해야 true를 반환한다.

  1. condition["or"] 존재하면:

    1. orConditions을 condition["or"]로 둔다.

    2. orConditions의 각 orCondition에 대해:

      1. 라우터 조건 매칭 알고리즘을 orCondition, serviceWorker, request로 실행한 결과가 true면 true를 반환한다.

    3. false를 반환한다.

  2. condition["not"] 존재하면:

    1. 라우터 조건 매칭 알고리즘을 condition["not"], serviceWorker, request로 실행한 결과가 true면 false를 반환한다.

    2. true를 반환한다.

  3. 그 외에는:

    참고: 라우터 조건 검증 알고리즘이 or, not과 다른 조건이 상호 배타적임을 보장한다.

    1. condition["urlPattern"] 존재하면:

      1. rawPattern을 condition["urlPattern"]로 둔다.

      2. pattern을 URL 패턴 파싱 알고리즘을 rawPattern, serviceWorker로 실행한 결과로 둔다.

      3. match 알고리즘을 pattern, request의 URL로 실행한 결과가 null이면 false를 반환한다.

    2. condition["requestMethod"] 존재하면:

      1. method을 condition["requestMethod"]로 둔다.

      2. method 정규화를 method로 실행한다.

      3. request의 method가 method와 다르면 false를 반환한다.

    3. condition["requestMode"] 존재하면:

      1. mode을 condition["requestMode"]로 둔다.

      2. request의 mode가 mode와 다르면 false를 반환한다.

    4. condition["requestDestination"] 존재하면:

      1. destination을 condition["requestDestination"]로 둔다.

      2. request의 destination이 destination과 다르면 false를 반환한다.

    5. condition["runningStatus"] 존재하면:

      1. runningStatus을 condition["runningStatus"]로 둔다.

      2. runningStatus가 "running"이고, serviceWorker가 실행 중이 아니면 false를 반환한다.

      3. runningStatus가 "not-running"이고, serviceWorker가 실행 중이면 false를 반환한다.

    6. true를 반환한다.

라우터 등록 제한 검사

입력

routerRules, 라우터 규칙 리스트

출력

불리언 값

참고: 라우터 조건은 _or와 not을 사용하여 복잡하게 중첩될 수 있습니다. 과도한 처리를 방지하기 위해, 이 알고리즘은 두 가지 제한을 둡니다. 첫째, 중첩된 모든 조건을 합한 총 조건 수는 1024를 초과할 수 없습니다. 둘째, 중첩 깊이는 10단계로 제한하여 계산량이 지수적으로 증가하는 것을 막습니다.

  1. result를 라우터 조건 카운트 결과로 둔다.

  2. result의 condition count를 1024로 설정한다.

  3. result의 quota exceeded를 false로 설정한다.

  4. 각 rule을 routerRules에서 반복하여:

    1. result를 내부 라우터 조건 카운트 알고리즘을 rule["condition"], result, 10으로 실행한 결과로 둔다.

    2. result의 quota exceeded가 true면 false를 반환한다.

  5. true를 반환한다.

내부 라우터 조건 카운트

입력

condition, RouterCondition

result, 라우터 조건 카운트 결과

depth, 숫자

출력

result, 라우터 조건 카운트 결과

  1. result의 condition count를 1 감소시킨다.

  2. result의 condition count가 0이거나, depth가 0이면:

    1. result의 quota exceeded를 true로 설정한다.

    2. result를 반환한다.

  3. condition["_or"]가 존재하면:

    1. depth를 1 감소시킨다.

    2. condition["_or"]의 각 orCondition에 대해:

      1. result를 내부 라우터 조건 카운트 알고리즘을 orCondition, result, depth로 실행한 결과로 둔다.

      2. result의 quota exceeded가 true면 result를 반환한다.

  4. 그 외에 condition["not"]가 존재하면:

    1. depth를 1 감소시킨다.

    2. result를 내부 라우터 조건 카운트 알고리즘을 condition["not"], result, depth로 실행한 결과로 둔다.

    3. result의 quota exceeded가 true면 result를 반환한다.

  5. result를 반환한다.

라우터 소스 확인

입력

serviceWorker, 서비스 워커

request, request

출력

RouterSource 또는 null

  1. 각 rule을 serviceWorker의 라우터 규칙 리스트에서 반복하여:

    1. 라우터 조건 매칭 알고리즘을 rule["condition"], serviceWorker, request로 실행한 결과가 true면, rule["source"]를 반환한다.

  2. null을 반환한다.

이벤트 생략 여부

입력

eventName, 문자열

serviceWorker, 서비스 워커

출력

불리언 값

참고: 불필요한 지연을 피하기 위해, 이 표준은 서비스 워커의 글로벌에서 이벤트 리스너가 최초 스크립트 실행 시 결정적으로 추가되지 않은 경우 이벤트 디스패치를 생략할 수 있도록 허용합니다.

  1. serviceWorker의 처리할 이벤트 타입 집합에 eventName이 포함되지 않으면, 사용자 에이전트는 true를 반환할 수 있습니다.

  2. false를 반환한다.

기능성 이벤트 발행

입력

eventName, 문자열

eventConstructor, ExtendableEvent를 확장하는 이벤트 생성자

registration, 서비스 워커 등록

initialization, eventConstructor에서 생성된 event에 대한 선택적 속성 초기화

postDispatchSteps, 활성 워커의 이벤트 루프에서 실행할 선택적 단계이며, dispatchedEvent는 디스패치된 eventConstructor 인스턴스로 설정됩니다.

출력

없음

  1. 단언: registration의 활성 워커는 null이 아닙니다.

  2. activeWorker를 registration의 활성 워커로 둡니다.

  3. eventName과 activeWorker로 이벤트를 건너뛸지 여부를 실행한 결과가 true이면 다음을 수행합니다.

    1. registration이 오래된 상태이면 병렬로 registration을 사용하여 소프트 업데이트 알고리즘을 실행합니다.

    2. 반환합니다.

  4. activeWorker의 상태가 "activating"이면 activeWorker의 상태가 "activated"가 될 때까지 기다립니다.

  5. activeWorker로 서비스 워커 실행 알고리즘을 실행한 결과가 실패이면 다음을 수행합니다.

    1. registration이 오래된 상태이면 병렬로 registration을 사용하여 소프트 업데이트 알고리즘을 실행합니다.

    2. 반환합니다.

  6. 다음 하위 단계를 실행하도록 task를 태스크로 큐에 추가합니다.

    1. event를 eventConstructor와 activeWorker의 전역 객체의 관련 Realm으로 이벤트를 생성한 결과로 둡니다.

    2. initialization이 null이 아니면 initialization으로 event를 초기화합니다.

    3. activeWorker의 전역 객체에서 event를 디스패치합니다.

    4. activeWorker와 event로 서비스 워커 확장 이벤트 집합 업데이트를 호출합니다.

    5. postDispatchSteps가 null이 아니면 event를 dispatchedEvent로 전달하여 postDispatchSteps를 실행합니다.

    task는 activeWorker의 이벤트 루프와 기능 이벤트 처리 태스크 소스를 반드시 사용해야 합니다.

  7. task가 실행되거나 폐기될 때까지 기다립니다.

  8. registration이 오래된 상태이면 병렬로 registration을 사용하여 소프트 업데이트 알고리즘을 실행합니다.

특정 serviceWorkerRegistration에서 "amazingthing" 이벤트(타입은 AmazingThingEvent)를 발동하고 이벤트 객체의 속성을 초기화하려면, 절차는 다음과 같다:
  1. Fire Functional Event "amazingthing"를 AmazingThingEvent를 사용하여 serviceWorkerRegistration에 대해 다음 속성으로 실행한다:

    propertyName

    value

    anotherPropertyName

    anotherValue

    그런 다음 dispatchedEvent로 다음 단계를 실행한다:

    1. dispatchedEvent로 서비스 워커의 이벤트 루프에서 필요한 작업을 수행한다.

초기화 단계와 포스트 디스패치 단계는 선택 사항이다. 필요하지 않다면, 절차는 다음과 같다:

  1. Fire Functional Event "whatever"를 ExtendableEvent 를 사용하여 serviceWorkerRegistration에 대해 실행한다.

서비스 워커 클라이언트 언로드 처리

사용자 에이전트는 서비스 워커 클라이언트가 문서 언로드 정리 단계 또는 종료를 통해 언로드될 때의 일부로 이 단계를 실행해야 한다.

입력

client, 서비스 워커 클라이언트

출력

없음

  1. 다음 단계를 원자적으로 실행한다.

  2. registration을 client가 사용하는 서비스 워커 등록으로 둔다.

  3. registration이 null이면, 이 단계를 중단한다.

  4. 다른 서비스 워커 클라이언트가 registration을 사용하고 있으면, 이 단계를 중단한다.

  5. registration이 등록 해제된 상태이면, registration을 사용하여 등록 지우기 시도를 호출한다.

  6. registration을 사용하여 활성화 시도를 호출한다.

사용자 에이전트 종료 처리

입력

없음

출력

없음

  1. 각 항목에 대해 다음을 수행합니다: registration (대상: 등록 맵의 값들):

    1. 만약 registration의 installing worker가 null이 아니면:

      1. 만약 registration의 waiting worker가 null이고 registration의 active worker가 null이면, Clear Registration을 registration에 대해 호출하고 루프의 다음 반복으로 계속한다.

      2. 그렇지 않으면 registration의 installing worker를 null로 설정한다.

    2. 만약 registration의 waiting worker가 null이 아니면, 병렬로:

      1. Activate를 registration에 대해 호출한다.

서비스 워커 확장 이벤트 집합 업데이트

입력

worker, service worker입니다.

event, ExtendableEvent입니다.

출력

없음

  1. 명제: event의 dispatch flag가 unset이다.

  2. 각 item에 대해 worker의 set of extended events:

    1. 만약 item이 active가 아니면, remove item를 worker의 set of extended events에서 제거한다.

  3. 만약 event가 active이면, append event를 worker의 set of extended events에 추가한다.

등록 해제

입력

job은 작업이다.

출력

없음

  1. registration을 등록 가져오기에 job의 스토리지 키와 job의 스코프 URL을 전달해서 얻는다.

  2. registration이 null이면:

    1. 작업 프로미스 해결을 job과 false로 호출한다.

    2. 작업 완료를 job과 함께 호출하고, 여기서 이 과정을 중단한다.

  3. 제거 등록 맵[(registration의 스토리지 키, job의 스코프 URL)].

  4. 작업 프로미스 해결을 job과 true로 호출한다.

  5. 등록 비우기 시도를 registration과 함께 호출한다.

    참고: 등록 비우기 시도가 여기서 등록 비우기를 트리거하지 않으면, 해당 등록을 사용하는 마지막 클라이언트가 언로드되거나 해당 등록의 서비스 워커에 대한 수명 연장 프로미스가 이행되거나 거부될 때 등록 비우기를 다시 시도합니다.

  6. 작업 완료를 job과 함께 호출한다.

등록 설정

입력

storage key, 저장소 키

scope, URL

updateViaCache, 캐시를 통한 업데이트 모드

출력

registration, 서비스 워커 등록

  1. 다음 단계를 원자적으로 실행합니다.

  2. scopeString을 프래그먼트 제외 플래그가 설정된 scope의 직렬화된 값으로 둡니다.

  3. registration을 서비스 워커 등록으로 새로 만들고, 그 저장소 키를 storage key로, 범위 URL을 scope로, 캐시를 통한 업데이트 모드를 updateViaCache로 설정합니다.

  4. 설정합니다 등록 맵[(storage key, scopeString)]을 registration으로.

  5. registration을 반환합니다.

등록 정리

입력

registration, service worker registration

출력

없음

  1. 다음 단계를 원자적으로 실행한다.

  2. 만약 registration의 installing worker가 null이 아니면:

    1. Terminate registration의 installing worker를 실행한다.

    2. Update Worker State 알고리즘을 registration의 installing worker와 "redundant"로 실행한다.

    3. Update Registration State 알고리즘을 registration, "installing", null로 실행한다.

  3. 만약 registration의 waiting worker가 null이 아니면:

    1. Terminate registration의 waiting worker를 실행한다.

    2. Update Worker State 알고리즘을 registration의 waiting worker와 "redundant"로 실행한다.

    3. Update Registration State 알고리즘을 registration, "waiting", null로 실행한다.

  4. 만약 registration의 active worker가 null이 아니면:

    1. Terminate registration의 active worker를 실행한다.

    2. Update Worker State 알고리즘을 registration의 active worker와 "redundant"로 실행한다.

    3. Update Registration State 알고리즘을 registration, "active", null로 실행한다.

등록 정리 시도

입력

registration, service worker registration

출력

없음

  1. Clear Registration을 registration에 대해 호출하라 단, 어떠한 service worker client도 registration를 사용하고 있지 않고 아래 모든 조건이 참일 때:

등록 상태 업데이트

입력

registration, service worker registration

target, 문자열 ( "installing", "waiting", "active" 중 하나)

source, service worker 또는 null

출력

없음

  1. registrationObjects를 registration과 연결된 모든 ServiceWorkerRegistration 객체를 포함하는 배열로 설정한다.

  2. target이 "installing"이면, 다음을 수행한다:

    1. registration의 설치 중인 워커를 source로 설정한다.

    2. registrationObjects의 각 registrationObject에 대해:

      1. registration의 설치 중인 워커가 null이면 registrationObject의 installing 속성을 null로 설정하고, 그렇지 않으면 registrationObject의 관련 설정 객체에서 registration의 설치 중인 워커를 나타내는 서비스 워커 객체를 가져온 결과로 설정하도록 태스크를 큐에 넣는다.

  3. 그렇지 않고 target이 "waiting"이면:

    1. registration의 대기 중인 워커를 source로 설정한다.

    2. registrationObjects의 각 registrationObject에 대해:

      1. 태스크를 큐에 추가하여, registration의 대기 중인 워커가 null이면 registrationObject의 waiting 속성을 null로 설정하고, 그렇지 않으면 registrationObject의 관련 설정 객체에서 registration의 대기 중인 워커를 나타내는 서비스 워커 객체를 가져온 결과로 설정한다.

  4. 그렇지 않고 target이 "active"이면:

    1. registration의 활성 워커를 source로 설정한다.

    2. registrationObjects의 각 registrationObject에 대해:

      1. 태스크를 큐에 추가하여, registration의 활성 워커가 null이면 registrationObject의 active 속성을 null로 설정하고, 그렇지 않으면 registrationObject의 관련 설정 객체에서 registration의 활성 워커를 나타내는 서비스 워커 객체를 가져온 결과로 설정한다.

    태스크는 반드시 registrationObject의 관련 설정 객체의 담당 이벤트 루프와 DOM 조작 태스크 소스를 사용해야 한다.

워커 상태 업데이트

입력

worker, service worker

state, service worker의 state

출력

없음

  1. 단언: state는 "parsed"가 아니다.

    참고: "parsed"는 초기 상태이다. 서비스 워커는 이 상태로 업데이트되는 일이 없다.

  2. worker의 상태를 state로 설정한다.

  3. settingsObjects를 환경 설정 객체 중 그 출처가 worker의 스크립트 URL의 출처인 모든 객체로 둔다.

  4. settingsObjects의 각 settingsObject에 대해, settingsObject의 담당 이벤트 루프에서 DOM 조작 태스크 소스를 사용하여 다음 단계를 실행하도록 태스크를 큐에 추가한다:

    1. objectMap을 settingsObject의 서비스 워커 객체 맵으로 둔다.

    2. objectMap[worker]이 존재하지 않으면, 이 단계들을 중단한다.

    3. workerObj를 objectMap[worker]으로 둔다.

    4. workerObj의 state 를 state로 설정한다.

    5. workerObj에서 statechange라는 이름의 이벤트를 발생시킨다.

컨트롤러 변경 알림

입력

client, 서비스 워커 클라이언트

출력

없음

  1. 단언: client는 null이 아니다.

  2. client가 환경 설정 객체이면, client가 연결된 ServiceWorkerContainer 객체에서 controllerchange라는 이름의 이벤트를 발생시키도록 태스크를 큐에 추가한다.

태스크는 반드시 client의 담당 이벤트 루프와 DOM 조작 태스크 소스를 사용해야 한다.

서비스 워커 등록 매칭

입력

storage key, storage key

clientURL, URL

출력

service worker registration

  1. 다음 단계를 원자적으로 실행한다.

  2. clientURLString를 serialized clientURL로 둔다.

  3. matchingScopeString를 빈 문자열로 둔다.

  4. scopeStringSet를 빈 목록으로 둔다.

  5. 각 항목에 대해 다음을 수행합니다: (entry storage key, entry scope) (대상: 등록 맵의 키들):

    1. 만약 storage key가 entry storage key와 equals하면, append entry scope를 scopeStringSet의 끝에 추가한다.

  6. matchingScopeString를 scopeStringSet 중 clientURLString이 시작하는 가장 긴 값으로 설정한다(존재하면).

    참고: 이 단계의 URL 문자열 매칭은 경로 구조 기반이 아닌 접두사 기반이다. 예: 클라이언트 URL 문자열 "https://example.com/prefix-of/resource.html"은 "https://example.com/prefix"로 설정된 scope와 매치된다. URL 문자열 비교는 동일 출처 보안에 안전하다: HTTP(S) URL은 항상 origin 부분 끝에 슬래시가 붙은 형태로 serialized된다.

  7. matchingScope를 null로 둔다.

  8. 만약 matchingScopeString가 빈 문자열이 아니면:

    1. matchingScope를 parsing matchingScopeString의 결과로 둔다.

    2. 명제: matchingScope의 origin과 clientURL의 origin는 same origin이다.

  9. Get Registration를 storage key와 matchingScope로 실행한 결과를 반환한다.

등록 가져오기

입력

storage key, storage key

scope, URL

출력

service worker registration

  1. 다음 단계를 원자적으로 실행한다.

  2. scopeString를 빈 문자열로 둔다.

  3. 만약 scope가 null이 아니면, scopeString를 serialized scope로, exclude fragment flag를 설정한 상태로 둔다.

  4. 각 항목에 대해 다음을 수행합니다: (entry storage key, entry scope) → registration (대상: 등록 맵):

    1. 만약 storage key가 entry storage key와 equals하고 scopeString가 entry scope와 매치되면, registration을 반환한다.

  5. null을 반환한다.

최신 워커 가져오기

입력

registration, service worker registration

출력

newestWorker, service worker

  1. 다음 단계를 원자적으로 실행한다.

  2. newestWorker를 null로 둔다.

  3. 만약 registration의 installing worker가 null이 아니면 newestWorker를 그 installing worker로 설정한다.

  4. 그렇지 않으면 만약 registration의 waiting worker가 null이 아니면 newestWorker를 그 waiting worker로 설정한다.

  5. 그렇지 않으면 만약 registration의 active worker가 null이 아니면 newestWorker를 그 active worker로 설정한다.

  6. newestWorker를 반환한다.

서비스 워커에 보류 중인 이벤트 없음

입력

worker, service worker

출력

True 또는 False, 불리언

  1. worker의 set of extended events의 각 event에 대해:

    1. 만약 event가 active이면 false를 반환한다.

  2. true를 반환한다.

클라이언트 생성

입력

client, service worker client

출력

clientObject, Client 객체

  1. clientObject를 새로운 Client 객체로 둔다.

  2. clientObject의 service worker client를 client로 설정한다.

  3. clientObject를 반환한다.

윈도우 클라이언트 생성

입력

client, service worker client

frameType, 문자열

visibilityState, 문자열

focusState, 불리언

ancestorOriginsList, 목록

출력

windowClient, WindowClient 객체

  1. windowClient를 새로운 WindowClient 객체로 둔다.

  2. windowClient의 service worker client를 client로 설정한다.

  3. windowClient의 frame type을 frameType으로 설정한다.

  4. windowClient의 visibility state를 visibilityState로 설정한다.

  5. windowClient의 focus state를 focusState로 설정한다.

  6. windowClient의 ancestor origins array를 ancestorOriginsList로부터 생성된 frozen array로 설정한다.

  7. 반환한다: windowClient.

프레임 타입 가져오기

입력

navigable, navigable

출력

frameType, 문자열

  1. 만약 navigable의 parent가 null이 아니면, "nested"를 반환한다.

  2. 만약 navigable의 active browsing context가 auxiliary browsing context이면 "auxiliary"를 반환한다.

  3. "top-level"를 반환한다.

Get Client Promise 해석

입력

client, service worker client

promise, promise

출력

없음

  1. client가 환경 설정 객체이면:

    1. client가 보안 컨텍스트가 아니면, promise의 관련 설정 객체의 담당 이벤트 루프에서 DOM 조작 태스크 소스를 사용하여 promise를 "SecurityError" DOMException으로 거부하도록 태스크를 큐에 추가하고, 이 단계들을 중단한다.

  2. 그렇지 않으면:

    1. client의 생성 URL이 잠재적으로 신뢰할 수 있는 URL이 아니면, promise의 관련 설정 객체의 담당 이벤트 루프에서 DOM 조작 태스크 소스를 사용하여 promise를 "SecurityError" DOMException으로 거부하도록 태스크를 큐에 추가하고, 이 단계들을 중단한다.

  3. client가 환경 설정 객체이고 윈도우 클라이언트가 아니면:

    1. clientObject를 client를 인수로 사용하여 클라이언트 생성 알고리즘을 실행한 결과로 둔다.

    2. promise의 관련 설정 객체의 담당 이벤트 루프에서 DOM 조작 태스크 소스를 사용하여 promise를 clientObject로 이행하도록 태스크를 큐에 추가하고, 이 단계들을 중단한다.

  4. 그렇지 않으면:

    1. browsingContext를 null로 둔다.

    2. client가 환경 설정 객체이면, browsingContext를 client의 전역 객체의 브라우징 컨텍스트로 설정한다.

    3. 그렇지 않으면, browsingContext를 client의 대상 브라우징 컨텍스트로 설정한다.

    4. navigable을 browsingContext를 활성 브라우징 컨텍스트로 갖는 내비게이터블로 둔다.

    5. browsingContext의 이벤트 루프에서 사용자 상호작용 태스크 소스를 사용하여 다음 단계를 실행하도록 태스크를 큐에 추가한다:

      1. frameType을 navigable을 사용하여 프레임 유형 가져오기를 실행한 결과로 둔다.

      2. visibilityState를 browsingContext의 활성 문서의 visibilityState 속성 값으로 둔다.

      3. focusState를 browsingContext의 활성 문서를 인수로 사용하여 포커스 보유 단계를 실행한 결과로 둔다.

      4. ancestorOriginsList를 빈 목록으로 둔다.

      5. client가 윈도우 클라이언트이면, ancestorOriginsList를 browsingContext의 활성 문서의 상위 출처 목록에 연결된 목록으로 설정한다.

      6. promise의 관련 설정 객체의 담당 이벤트 루프에서 DOM 조작 태스크 소스를 사용하여 다음 단계를 실행하도록 태스크를 큐에 추가한다:

        1. client의 폐기됨 플래그가 설정되어 있으면, promise를 undefined로 이행하고 이 단계들을 중단한다.

        2. windowClient를 client, frameType, visibilityState, focusState, ancestorOriginsList를 사용하여 윈도우 클라이언트 생성을 실행한 결과로 둔다.

        3. promise를 windowClient로 이행한다.

캐시 질의

입력

requestQuery, request

options, 선택적 CacheQueryOptions 객체

targetStorage, 선택적 request response list

출력

resultList, request response list

  1. resultList를 빈 list로 둔다.

  2. storage를 null로 둔다.

  3. 만약 선택 인자 targetStorage가 생략되었으면 storage를 relevant request response list로 설정한다.

  4. 그렇지 않으면 storage를 targetStorage로 설정한다.

  5. 각각 반복한다: requestResponse 의값은 storage의각항목이다:

    1. cachedRequest를 requestResponse의 request로 둔다.

    2. cachedResponse를 requestResponse의 response로 둔다.

    3. 만약 Request Matches Cached Item를 requestQuery, cachedRequest, cachedResponse, options로 실행한 결과가 true이면:

      1. requestCopy를 cachedRequest의 복사로 둔다.

      2. responseCopy를 cachedResponse의 복사로 둔다.

      3. requestCopy/responseCopy를 resultList에 추가한다.

  6. resultList를 반환한다.

요청이 캐시 항목과 일치

입력

requestQuery, 요청

request, 요청

response, 응답 또는 null, 선택 사항, 기본값은 null

options, CacheQueryOptions 객체, 선택 사항

출력

불리언

  1. 만약 options["ignoreMethod"] 가 false이고 request의 method가 `GET`이 아니면 false를 반환한다.

  2. queryURL를 requestQuery의 url로 둔다.

  3. cachedURL를 request의 url로 둔다.

  4. 만약 options["ignoreSearch"] 가 true이면:

    1. cachedURL의 query를 빈 문자열로 설정한다.

    2. queryURL의 query를 빈 문자열로 설정한다.

  5. 만약 queryURL가 equal하지 않으면( exclude fragment flag를 설정한 상태에서 ) false를 반환한다.

  6. 만약 response가 null이거나, options["ignoreVary"] 가 true이거나, response의 header list가 `Vary`를 포함하지 않으면 true를 반환한다.

  7. fieldValues를 list로, response의 `Vary` 헤더의 field-values에 해당하는 요소들로 채운다. 이때 해당 헤더의 이름은 Vary이고, 처리하는 대상은 그 헤더의 값이다.

  8. fieldValues의 각 fieldValue에 대해:

    1. 만약 fieldValue가 "*"와 매치되거나, fieldValue를 이름으로 하는 combined value(대상: request의 header list)가, requestQuery의 header list에서 같은 이름으로 계산된 combined value와 일치하지 않으면 false를 반환한다.

  9. true를 반환한다.

캐시 일괄 작업

입력

operations, list of cache batch operation 객체들

출력

resultList, request response list

  1. cache를 relevant request response list로 둔다.

  2. backupCache를 request response list의 새 복사본으로 둔다.

  3. addedItems를 빈 list로 둔다.

  4. 다음 하위 단계를 원자적으로 시도한다:

    1. resultList를 빈 list로 둔다.

    2. 각각 반복한다: operation 의값은 operations의각항목이다:

      1. 만약 operation의 type이 "delete"도 "put"도 아니면, throw TypeError를 발생시킨다.

      2. 만약 operation의 type이 "delete"이고 operation의 response가 null이 아니면, throw TypeError를 발생시킨다.

      3. Query Cache를 operation의 request, operation의 options, 그리고 addedItems로 실행한 결과가 비어 있지 않으면, throw "InvalidStateError" DOMException를 발생시킨다.

      4. requestResponses를 빈 list로 둔다.

      5. 만약 operation의 type이 "delete"이면:

        1. requestResponses를 Query Cache를 operation의 request와 operation의 options로 실행한 결과로 둔다.

        2. 각각 반복한다: requestResponse 의값은 requestResponses의각항목이다:

          1. Remove cache에서 requestResponse와 값이 일치하는 item을 제거한다.

      6. 그렇지 않으면 만약 operation의 type이 "put"이면:

        1. 만약 operation의 response가 null이면, throw TypeError를 발생시킨다.

        2. r를 operation의 request에 연관된 request로 둔다.

        3. 만약 r의 url의 scheme이 "http" 또는 "https"가 아니면, throw TypeError를 발생시킨다.

        4. 만약 r의 method가 `GET`이 아니면, throw TypeError를 발생시킨다.

        5. 만약 operation의 options가 null이 아니면, throw TypeError를 발생시킨다.

        6. requestResponses를 Query Cache를 operation의 request로 실행한 결과로 둔다.

        7. 각각 반복한다: requestResponse 의값은 requestResponses의각항목이다:

          1. Remove cache에서 requestResponse와 값이 일치하는 item을 제거한다.

        8. Append operation의 request/operation의 response를 cache에 추가한다.

        9. 만약 이전 두 단계의 캐시 쓰기 작업이 할당된 쿼터 한도를 초과하여 실패하면, throw QuotaExceededError를 발생시킨다.

        10. Append operation의 request/operation의 response를 addedItems에 추가한다.

      7. Append operation의 request/operation의 response를 resultList에 추가한다.

    3. resultList를 반환한다.

  5. 만약 위에서 예외가 thrown되었다면, 다음을 실행한다:

    1. Remove items을 모두 relevant request response list에서 제거한다.

    2. 각각 반복한다: requestResponse 의값은 backupCache의각항목이다:

      1. Append requestResponse를 relevant request response list에 추가한다.

    3. Throw 예외를 다시 던진다.

    참고: 예외가 thrown될 때, 구현은 배치 작업 중에 캐시 저장소에 대해 수행한 변경 사항을 되돌린다(롤백)한다.

비동기 모듈 여부 확인

입력

record, Module Record

moduleMap, module map

base, URL

seen, set of URLs

출력

불리언

  1. 만약 record가 Cyclic Module Record가 아니면:

    1. false를 반환한다.

  2. 만약 record.[[Async]]가 true이면:

    1. true를 반환한다.

  3. For each 문자열 requested of record.[[RequestedModules]]에 대해:

    1. url를 resolving a module specifier를 base와 requested로 실행한 결과로 둔다.

    2. 명제: url는 절대 failure가 아니다. 왜냐하면 동일한 두 인자로 이미 모듈 스페시파이어 해석이 성공적이었기 때문이다.

    3. 만약 seen이 url을 포함하지 않으면:

      1. Append url을 seen에 추가한다.

      2. 만약 moduleMap[url]에 record가 없으면:

        1. false를 반환한다.

      3. 만약 Is Async Module를 moduleMap[url]'s record, moduleMap, base, seen로 실행한 결과가 true이면:

        1. true를 반환한다.

  4. false를 반환한다.

경쟁 응답 조회

입력

request, request

출력

response 또는 null

  1. registration을 null로 둔다.

  2. request가 비하위 리소스 요청이면:

    1. request의 예약된 클라이언트가 null이면, null을 반환한다.

    2. storage key를 request의 예약된 클라이언트가 주어졌을 때 스토리지 키를 얻는 알고리즘을 실행한 결과로 둔다.

    3. registration을 storage key와 request의 URL이 주어졌을 때 서비스 워커 등록 일치시키기를 실행한 결과로 설정한다.

  3. 그렇지 않고 request가 하위 리소스 요청이면:

    1. client를 request의 클라이언트로 둔다.

    2. client의 활성 서비스 워커가 null이면, null을 반환한다.

    3. registration을 client의 활성 서비스 워커의 포함 서비스 워커 등록으로 설정한다.

  4. 그렇지 않으면, null을 반환한다.

  5. activeWorker를 registration의 활성 워커로 둔다.

  6. map을 activeWorker의 전역 객체의 경쟁 응답 맵으로 둔다.

  7. map[request]이 존재하면:

    1. entry를 map[request]으로 둔다.

    2. entry의 값이 "pending"이 아닐 때까지 기다린다.

    3. entry의 값이 응답이면, entry의 값을 복제한 결과를 반환한다.

  8. null을 반환한다.

부록 B: 확장된 HTTP 헤더

서비스 워커 스크립트 요청

fetch를 통해 서비스 워커의 스크립트 리소스를 요청하는 HTTP 요청에는 다음 헤더가 포함됩니다:

`Service-Worker`

이 요청이 서비스 워커의 스크립트 리소스 요청임을 나타냅니다.

참고: 이 헤더는 관리자가 요청 로그를 남기고 위협을 감지하는 데 도움이 됩니다.

서비스 워커 스크립트 응답

서비스 워커의 스크립트 리소스 요청에 대한 HTTP 응답에는 다음 헤더가 포함될 수 있습니다:

`Service-Worker-Allowed`

사용자 에이전트가 경로 제한(스크립트가 scope url을 제어할 수 있는 최대 경로)을 주어진 값으로 재정의함을 나타냅니다.

참고: 값은 URL입니다. 상대 URL이 주어지면, 스크립트의 URL을 기준으로 파싱됩니다.

기본 scope:
// 최대 허용 범위는 기본적으로 스크립트가 위치한 경로로 설정됩니다
// 이 예시에서는 "/js/"입니다
navigator.serviceWorker.register("/js/sw.js").then(() => {
  console.log("기본 scope '/js/'로 설치 성공.");
});
Service-Worker-Allowed 헤더 없는 상위 경로:
// 스크립트 위치보다 상위 경로로 scope 설정
// 응답에 Service-Worker-Allowed 헤더 없음
navigator.serviceWorker.register("/js/sw.js", { scope: "/" }).catch(() => {
  console.error("경로 제한 위반으로 설치 실패.");
});
Service-Worker-Allowed 헤더가 포함된 상위 경로:
// 스크립트 위치보다 상위 경로로 scope 설정
// 응답에 "Service-Worker-Allowed : /" 포함
navigator.serviceWorker.register("/js/sw.js", { scope: "/" }).then(() => {
  console.log("최대 허용 scope가 '/'로 재정의되어 설치 성공.");
});
Service-Worker-Allowed 헤더가 있어도 경로 제한 위반:
// 스크립트 위치보다 상위 경로로 scope 설정
// 응답에 "Service-Worker-Allowed : /foo" 포함
navigator.serviceWorker.register("/foo/bar/sw.js", { scope: "/" }).catch(() => {
  console.error("scope가 재정의된 최대 허용 scope를 벗어나 설치 실패.");
});

문법

ABNF는 서비스 워커의 스크립트 리소스 요청 및 응답에서 사용되는 헤더 값에 대해 정의합니다:

Service-Worker = %x73.63.72.69.70.74 ; "script", 대소문자 구분

참고: Service-Worker-Allowed 헤더 값의 유효성 검사는 ABNF 대신 URL 파싱 알고리즘(갱신 알고리즘)으로 수행됩니다.

8. 감사의 글

Andrew Betts에게 동료들과 함께하는 작은 워크숍을 조직하고 진행해주신 데 깊이 감사드립니다. 참석자: Jake Archibald, Jackson Gabbard, Tobie Langel, Robin Berjon, Patrick Lauke, Christian Heilmann. 논의의 명확성과 그날 제시된 사용 사례들 덕분에 많은 것이 가능해졌습니다. 또한 오프라인 문제의 중요성을 일깨워준 Andrew에게 다시 한번 감사드립니다. 그가 EdgeConf를 조직하고 오프라인을 지속적인 주제로 삼은 덕분에 본 작업의 진전에 여러 기회와 연결이 생겼습니다.

Anne van Kesteren은 서비스 워커 개발 과정에서 웹 플랫폼의 심오한 지식과 표준화 경험을 아낌없이 공유해주셨습니다. URL, HTTP Fetch, Promises, DOM의 실제 동작을 기술한 그의 이전 작업 없이는 이 규격이 완성될 수 없었을 것입니다. Ian Hickson의 엄밀한 Web Worker 규격 역시 본 규격의 기반이 되었습니다. 그에게 깊은 감사를 전합니다.

순서는 없지만, 설계 방향과 논의에 깊이 감사드릴 분들: Jungkee Song, Alec Flett, David Barrett-Kahn, Aaron Boodman, Michael Nordman, Tom Ashworth, Kinuko Yasuda, Darin Fisher, Jonas Sicking, Jesús Leganés Combarro, Mark Christian, Dave Hermann, Yehuda Katz, François Remy, Ilya Grigorik, Will Chan, Domenic Denicola, Nikhil Marathe, Yves Lafon, Adam Barth, Greg Simon, Devdatta Akhawe, Dominic Cooney, Jeffrey Yasskin, Joshua Bell, Boris Zbarsky, Matt Falkenhagen, Tobie Langel, Gavin Peters, Ben Kelly, Hiroki Nakagawa, Jake Archibald, Josh Soref, Jinho Bang, Yutaka Hirano, Michael(tm) Smith, isonmad, Ali Alabbas, Philip Jägenstedt, Mike Pennisi, Eric Willigers.

Jason Weber, Chris Wilson, Paul Kinlan, Ehsan Akhgari, Daniel Austin은 요구사항과 표준화 과정에서 귀중한 피드백을 제공해주셨습니다.

저자들은 Dimitri Glazkov의 스크립트 및 포맷팅 도구에도 감사드립니다. 이 규격 제작에 필수적이었으며 많은 가르침도 받았습니다.

Vivian Cromwell, Greg Simon, Alex Komoroske, Wonsuk Lee, Seojin Kim에게도 전문적인 지원에 깊이 감사드립니다.

적합성

문서 관례

적합성 요구사항은 설명적 단언과 RFC 2119 용어의 조합으로 표현됩니다. 현행 표준의 규범적 부분에서 “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, “OPTIONAL”과 같은 주요 키워드는 RFC 2119에서 설명된 대로 해석해야 합니다. 그러나 가독성을 위해, 이 문서에서는 이러한 단어가 모두 대문자로 표시되지 않습니다.

이 명세의 모든 텍스트는 규범적이며, 명시적으로 비규범적이라고 표시된 섹션, 예시, 그리고 참고를 제외합니다. [RFC2119]

이 명세의 예시는 “예를 들어”라는 말로 시작하거나, class="example"를 사용하여 규범적 텍스트와 구분합니다, 예시:

이것은 참고용 예시입니다.

참고는 “참고”라는 단어로 시작하며, class="note"로 규범적 텍스트와 구분합니다, 예시:

참고, 이것은 참고용 설명입니다.

적합성 알고리즘

알고리즘 내에서 명령형으로 표현된 요구사항 (예: "앞의 공백 문자를 모두 제거한다" 또는 "false를 반환하고 이 단계를 중단한다")는 알고리즘을 소개하는 키워드("must", "should", "may" 등)의 의미로 해석해야 합니다.

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

색인

이 명세에서 정의된 용어

참조로 정의된 용어

참조

규범적 참조

[CSP-NEXT]
스크립팅 정책. 편집자 초안. URL: https://wicg.github.io/csp-next/scripting-policy.html
[CSP3]
Mike West; Antonio Sartori. 콘텐츠 보안 정책 Level 3. 2026년 8월 13일. WD. URL: https://www.w3.org/TR/CSP3/
[DOM]
Anne van Kesteren. DOM 표준. 현행 표준. URL: https://dom.spec.whatwg.org/
[ECMASCRIPT]
ECMAScript 언어 명세. URL: https://tc39.es/ecma262/multipage/
[FETCH]
Anne van Kesteren. Fetch 표준. 현행 표준. URL: https://fetch.spec.whatwg.org/
[FileAPI]
Marijn Kruisselbrink. File API. 2026년 6월 4일. WD. URL: https://www.w3.org/TR/FileAPI/
[HR-TIME-3]
Yoav Weiss. 고해상도 시간. 2026년 3월 24일. WD. URL: https://www.w3.org/TR/hr-time-3/
[HTML]
Anne van Kesteren; et al. HTML 표준. 현행 표준. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra 표준. 현행 표준. URL: https://infra.spec.whatwg.org/
[MIMESNIFF]
Gordon P. Hemsley. MIME 스니핑 표준. 현행 표준. URL: https://mimesniff.spec.whatwg.org/
[NAVIGATION-TIMING-2]
Yoav Weiss; Noam Rosenthal. Navigation Timing Level 2. 2026년 2월 25일. WD. URL: https://www.w3.org/TR/navigation-timing-2/
[PAGE-LIFECYCLE]
Page Lifecycle. 초안 커뮤니티 그룹 보고서. URL: https://wicg.github.io/page-lifecycle/
[RESOURCE-TIMING]
Yoav Weiss; Noam Rosenthal. Resource Timing. 2026년 4월 20일. CRD. URL: https://www.w3.org/TR/resource-timing/
[RFC2119]
S. Bradner. 요구 수준을 나타내기 위해 RFC에서 사용하는 핵심 단어. 1997년 3월. 현재 모범 관행. URL: https://datatracker.ietf.org/doc/html/rfc2119
[RFC5234]
D. Crocker, Ed.; P. Overell. 구문 명세를 위한 확장 BNF: ABNF. 2008년 1월. 인터넷 표준. URL: https://www.rfc-editor.org/info/rfc5234/
[RFC7230]
R. Fielding, Ed.; J. Reschke, Ed.. 하이퍼텍스트 전송 프로토콜(HTTP/1.1): 메시지 구문 및 라우팅. 2014년 6월. 제안 표준. URL: https://httpwg.org/specs/rfc7230.html
[RFC7231]
R. Fielding, Ed.; J. Reschke, Ed.. 하이퍼텍스트 전송 프로토콜(HTTP/1.1): 의미론 및 콘텐츠. 2014년 6월. 제안 표준. URL: https://httpwg.org/specs/rfc7231.html
[SCREEN-CAPTURE]
Jan-Ivar Bruaroey; Elad Alon. 화면 캡처. 2026년 7월 23일. WD. URL: https://www.w3.org/TR/screen-capture/
[SECURE-CONTEXTS]
Mike West. 보안 컨텍스트. 2023년 11월 10일. CRD. URL: https://www.w3.org/TR/secure-contexts/
[STORAGE]
Anne van Kesteren. Storage 표준. 현행 표준. URL: https://storage.spec.whatwg.org/
[STREAMS]
Adam Rice; et al. Streams 표준. 현행 표준. URL: https://streams.spec.whatwg.org/
[TRUSTED-TYPES]
Krzysztof Kotowicz. Trusted Types. 2026년 6월 23일. WD. URL: https://www.w3.org/TR/trusted-types/
[URL]
Anne van Kesteren. URL 표준. 현행 표준. URL: https://url.spec.whatwg.org/
[URLPATTERN]
Ben Kelly; Jeremy Roman; 宍戸俊哉 (Shunya Shishido). URL Pattern 표준. 현행 표준. URL: https://urlpattern.spec.whatwg.org/
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL 표준. 현행 표준. URL: https://webidl.spec.whatwg.org/

참고용 참조

[UNSANCTIONED-TRACKING]
비인가 웹 추적. 2015년 7월 17일. W3C TAG의 판정. URL: https://www.w3.org/2001/tag/doc/unsanctioned-tracking/

IDL 색인

[SecureContext, Exposed=(Window,Worker)]
interface ServiceWorker : EventTarget {
  readonly attribute USVString scriptURL;
  readonly attribute ServiceWorkerState state;
  undefined postMessage(any message, sequence<object> transfer);
  undefined postMessage(any message, optional StructuredSerializeOptions options = {});

  // event
  attribute EventHandler onstatechange;
};
ServiceWorker includes AbstractWorker;

enum ServiceWorkerState {
  "parsed",
  "installing",
  "installed",
  "activating",
  "activated",
  "redundant"
};

[SecureContext, Exposed=(Window,Worker)]
interface ServiceWorkerRegistration : EventTarget {
  readonly attribute ServiceWorker? installing;
  readonly attribute ServiceWorker? waiting;
  readonly attribute ServiceWorker? active;
  [SameObject] readonly attribute NavigationPreloadManager navigationPreload;

  readonly attribute USVString scope;
  readonly attribute ServiceWorkerUpdateViaCache updateViaCache;

  [NewObject] Promise<ServiceWorkerRegistration> update();
  [NewObject] Promise<boolean> unregister();

  // event
  attribute EventHandler onupdatefound;
};

enum ServiceWorkerUpdateViaCache {
  "imports",
  "all",
  "none"
};

partial interface Navigator {
  [SecureContext, SameObject] readonly attribute ServiceWorkerContainer serviceWorker;
};

partial interface WorkerNavigator {
  [SecureContext, SameObject] readonly attribute ServiceWorkerContainer serviceWorker;
};

[SecureContext, Exposed=(Window,Worker)]
interface ServiceWorkerContainer : EventTarget {
  readonly attribute ServiceWorker? controller;
  readonly attribute Promise<ServiceWorkerRegistration> ready;

  [NewObject] Promise<ServiceWorkerRegistration> register((TrustedScriptURL or USVString) scriptURL, optional RegistrationOptions options = {});

  [NewObject] Promise<(ServiceWorkerRegistration or undefined)> getRegistration(optional USVString clientURL = "");
  [NewObject] Promise<FrozenArray<ServiceWorkerRegistration>> getRegistrations();

  undefined startMessages();


  // events
  attribute EventHandler oncontrollerchange;
  attribute EventHandler onmessage; // event.source of message events is ServiceWorker object
  attribute EventHandler onmessageerror;
};

dictionary RegistrationOptions {
  USVString scope;
  WorkerType type = "classic";
  ServiceWorkerUpdateViaCache updateViaCache = "imports";
};

[SecureContext, Exposed=(Window,Worker)]
interface NavigationPreloadManager {
  Promise<undefined> enable();
  Promise<undefined> disable();
  Promise<undefined> setHeaderValue(ByteString value);
  Promise<NavigationPreloadState> getState();
};

dictionary NavigationPreloadState {
  boolean enabled = false;
  ByteString headerValue;
};

[Global=(Worker,ServiceWorker), Exposed=ServiceWorker, SecureContext]
interface ServiceWorkerGlobalScope : WorkerGlobalScope {
  [SameObject] readonly attribute Clients clients;
  [SameObject] readonly attribute ServiceWorkerRegistration registration;
  [SameObject] readonly attribute ServiceWorker serviceWorker;

  [NewObject] Promise<undefined> skipWaiting();

  attribute EventHandler oninstall;
  attribute EventHandler onactivate;
  attribute EventHandler onfetch;

  attribute EventHandler onmessage;
  attribute EventHandler onmessageerror;
};

[Exposed=ServiceWorker]
interface Client {
  readonly attribute USVString url;
  readonly attribute FrameType frameType;
  readonly attribute DOMString id;
  readonly attribute ClientType type;
  undefined postMessage(any message, sequence<object> transfer);
  undefined postMessage(any message, optional StructuredSerializeOptions options = {});
};

[Exposed=ServiceWorker]
interface WindowClient : Client {
  readonly attribute VisibilityState visibilityState;
  readonly attribute boolean focused;
  [SameObject] readonly attribute FrozenArray<USVString> ancestorOrigins;
  [NewObject] Promise<WindowClient> focus();
  [NewObject] Promise<WindowClient?> navigate(USVString url);
};

enum FrameType {
  "auxiliary",
  "top-level",
  "nested",
  "none"
};

[Exposed=ServiceWorker]
interface Clients {
  // The objects returned will be new instances every time
  [NewObject] Promise<(Client or undefined)> get(DOMString id);
  [NewObject] Promise<FrozenArray<Client>> matchAll(optional ClientQueryOptions options = {});
  [NewObject] Promise<WindowClient?> openWindow(USVString url);
  [NewObject] Promise<undefined> claim();
};

dictionary ClientQueryOptions {
  boolean includeUncontrolled = false;
  ClientType type = "window";
};

enum ClientType {
  "window",
  "worker",
  "sharedworker",
  "all"
};

[Exposed=ServiceWorker]
interface ExtendableEvent : Event {
  constructor(DOMString type, optional ExtendableEventInit eventInitDict = {});
  undefined waitUntil(Promise<any> f);
};

dictionary ExtendableEventInit : EventInit {
  // Defined for the forward compatibility across the derived events
};

[Exposed=ServiceWorker]
interface InstallEvent : ExtendableEvent {
  constructor(DOMString type, optional ExtendableEventInit eventInitDict = {});
  Promise<undefined> addRoutes((RouterRule or sequence<RouterRule>) rules);
};

dictionary RouterRule {
  required RouterCondition condition;
  required RouterSource source;
};

dictionary RouterCondition {
  URLPatternCompatible urlPattern;
  ByteString requestMethod;
  RequestMode requestMode;
  RequestDestination requestDestination;
  RunningStatus runningStatus;

  sequence<RouterCondition> _or;
  RouterCondition not;
};

typedef (RouterSourceDict or RouterSourceEnum) RouterSource;

dictionary RouterSourceDict {
  DOMString cacheName;
};

enum RunningStatus { "running", "not-running" };
enum RouterSourceEnum {
  "cache",
  "fetch-event",
  "network",
  "race-network-and-fetch-handler"
};

[Exposed=ServiceWorker]
interface FetchEvent : ExtendableEvent {
  constructor(DOMString type, FetchEventInit eventInitDict);
  [SameObject] readonly attribute Request request;
  readonly attribute Promise<any> preloadResponse;
  readonly attribute DOMString clientId;
  readonly attribute DOMString resultingClientId;
  readonly attribute DOMString replacesClientId;
  readonly attribute Promise<undefined> handled;

  undefined respondWith(Promise<Response> r);
};

dictionary FetchEventInit : ExtendableEventInit {
  required Request request;
  Promise<any> preloadResponse;
  DOMString clientId = "";
  DOMString resultingClientId = "";
  DOMString replacesClientId = "";
  Promise<undefined> handled;
};

[Exposed=ServiceWorker]
interface ExtendableMessageEvent : ExtendableEvent {
  constructor(DOMString type, optional ExtendableMessageEventInit eventInitDict = {});
  readonly attribute any data;
  readonly attribute USVString origin;
  readonly attribute DOMString lastEventId;
  [SameObject] readonly attribute (Client or ServiceWorker or MessagePort)? source;
  readonly attribute FrozenArray<MessagePort> ports;
};

dictionary ExtendableMessageEventInit : ExtendableEventInit {
  any data = null;
  USVString origin = "";
  DOMString lastEventId = "";
  (Client or ServiceWorker or MessagePort)? source = null;
  sequence<MessagePort> ports = [];
};

partial interface mixin WindowOrWorkerGlobalScope {
  [SecureContext, SameObject] readonly attribute CacheStorage caches;
};

[SecureContext, Exposed=(Window,Worker)]
interface Cache {
  [NewObject] Promise<(Response or undefined)> match(RequestInfo request, optional CacheQueryOptions options = {});
  [NewObject] Promise<FrozenArray<Response>> matchAll(optional RequestInfo request, optional CacheQueryOptions options = {});
  [NewObject] Promise<undefined> add(RequestInfo request);
  [NewObject] Promise<undefined> addAll(sequence<RequestInfo> requests);
  [NewObject] Promise<undefined> put(RequestInfo request, Response response);
  [NewObject] Promise<boolean> delete(RequestInfo request, optional CacheQueryOptions options = {});
  [NewObject] Promise<FrozenArray<Request>> keys(optional RequestInfo request, optional CacheQueryOptions options = {});
};

dictionary CacheQueryOptions {
  boolean ignoreSearch = false;
  boolean ignoreMethod = false;
  boolean ignoreVary = false;
};

[SecureContext, Exposed=(Window,Worker)]
interface CacheStorage {
  [NewObject] Promise<(Response or undefined)> match(RequestInfo request, optional MultiCacheQueryOptions options = {});
  [NewObject] Promise<boolean> has(DOMString cacheName);
  [NewObject] Promise<Cache> open(DOMString cacheName);
  [NewObject] Promise<boolean> delete(DOMString cacheName);
  [NewObject] Promise<sequence<DOMString>> keys();
};

dictionary MultiCacheQueryOptions : CacheQueryOptions {
  DOMString cacheName;
};

이슈 색인

이 섹션의 동작은 아직 완전히 명세되지 않았으며, HTML 현행 표준에서 명세될 예정입니다. 이 작업은 이슈와 풀 리퀘스트에서 추적되고 있습니다. ↵
아직 생성되지 않은 environment settings object를 사용하는 것에 대해. 서비스 워커는 다른 웹 워커와는 고유한 처리 모델을 가지므로 이를 사용합니다. HTML 표준의 스크립트 페칭 알고리즘은 원래 다른 웹 워커를 위해 설계되었으며 실행 환경의 environment settings object를 필요로 하지만, 서비스 워커는 갱신 알고리즘에서 스크립트를 별도로 가져오고, 이후 Run Service Worker 알고리즘을 통해 여러 번 스크립트를 실행합니다. ↵
HTML의 클래식 워커 스크립트 가져오기 알고리즘과 모듈 워커 스크립트 그래프 가져오기 알고리즘은 job의 client를 인자로 받습니다. Soft Update 알고리즘에서 전달될 때 job의 client는 null입니다. ↵
✔MDN

Cache/add

In all current engines.

Firefox41+Safari11.1+Chrome44+
Opera?Edge79+
Edge (Legacy)16+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet4.0+Opera Mobile?
✔MDN

Cache/addAll

In all current engines.

Firefox41+Safari11.1+Chrome46+
Opera?Edge79+
Edge (Legacy)16+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

Cache/delete

In all current engines.

Firefox41+Safari11.1+Chrome43+
Opera?Edge79+
Edge (Legacy)16+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

Cache/keys

In all current engines.

Firefox41+Safari11.1+Chrome43+
Opera?Edge79+
Edge (Legacy)16+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

Cache/match

In all current engines.

Firefox41+Safari11.1+Chrome43+
Opera?Edge79+
Edge (Legacy)16+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

Cache/matchAll

In all current engines.

Firefox41+Safari11.1+Chrome47+
Opera34+Edge79+
Edge (Legacy)16+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

Cache/put

In all current engines.

Firefox41+Safari11.1+Chrome43+
Opera?Edge79+
Edge (Legacy)16+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet4.0+Opera Mobile?
✔MDN

Cache

In all current engines.

Firefox41+Safari11.1+Chrome40+
Opera?Edge79+
Edge (Legacy)16+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet4.0+Opera Mobile?
✔MDN

CacheStorage/delete

In all current engines.

Firefox41+Safari11.1+Chrome40+
Opera?Edge79+
Edge (Legacy)16+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

CacheStorage/has

In all current engines.

Firefox41+Safari11.1+Chrome40+
Opera?Edge79+
Edge (Legacy)16+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

CacheStorage/keys

In all current engines.

Firefox41+Safari11.1+Chrome40+
Opera?Edge79+
Edge (Legacy)16+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

CacheStorage/match

In all current engines.

Firefox41+Safari11.1+Chrome54+
Opera?Edge79+
Edge (Legacy)16+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

CacheStorage/open

In all current engines.

Firefox41+Safari11.1+Chrome40+
Opera?Edge79+
Edge (Legacy)16+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

CacheStorage

In all current engines.

Firefox41+Safari11.1+Chrome43+
Opera?Edge79+
Edge (Legacy)16+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

Client/frameType

In all current engines.

Firefox44+Safari11.1+Chrome43+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

Client/id

In all current engines.

Firefox44+Safari11.1+Chrome40+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

Client/postMessage

In all current engines.

Firefox44+Safari11.1+Chrome40+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

Client/type

In all current engines.

Firefox54+Safari11.1+Chrome60+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

Client/url

In all current engines.

Firefox44+Safari11.1+Chrome40+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

Client

In all current engines.

Firefox44+Safari11.1+Chrome40+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

Clients/claim

In all current engines.

Firefox44+Safari11.1+Chrome42+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

Clients/get

In all current engines.

Firefox45+Safari11.1+Chrome51+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

Clients/matchAll

In all current engines.

Firefox54+Safari11.1+Chrome42+
Opera29+Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile29+
✔MDN

Clients/openWindow

In all current engines.

Firefox44+Safari11.1+Chrome40+
Opera38+Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile41+
✔MDN

Clients

In all current engines.

Firefox44+Safari11.1+Chrome40+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

ExtendableEvent/ExtendableEvent

In all current engines.

Firefox44+Safari11.1+Chrome41+
Opera24+Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile24+
✔MDN

ExtendableEvent/waitUntil

In all current engines.

Firefox44+Safari11.1+Chrome40+
Opera24+Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile24+
✔MDN

ExtendableEvent

In all current engines.

Firefox44+Safari11.1+Chrome40+
Opera24+Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile24+
✔MDN

ExtendableMessageEvent/ExtendableMessageEvent

In all current engines.

Firefox44+Safari11.1+Chrome51+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

ExtendableMessageEvent/data

In all current engines.

Firefox44+Safari11.1+Chrome51+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

ExtendableMessageEvent/lastEventId

In all current engines.

Firefox44+Safari11.1+Chrome51+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

ExtendableMessageEvent/origin

In all current engines.

Firefox44+Safari11.1+Chrome51+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

ExtendableMessageEvent/ports

In all current engines.

Firefox44+Safari11.1+Chrome51+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

ExtendableMessageEvent/source

In all current engines.

Firefox44+Safari11.1+Chrome51+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

ExtendableMessageEvent

In all current engines.

Firefox44+Safari11.1+Chrome51+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

FetchEvent/FetchEvent

In all current engines.

Firefox44+Safari11.1+Chrome44+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

FetchEvent/clientId

In all current engines.

Firefox45+Safari11.1+Chrome49+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

FetchEvent/handled

In all current engines.

Firefox84+Safari16+Chrome86+
Opera?Edge86+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

FetchEvent/preloadResponse

In all current engines.

Firefox99+Safari15.4+Chrome59+
Opera?Edge79+
Edge (Legacy)18IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
⚠MDN

FetchEvent/replacesClientId

In no current engines.

FirefoxNoneSafariNoneChromeNone
Opera?EdgeNone
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

FetchEvent/request

In all current engines.

Firefox44+Safari11.1+Chrome40+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

FetchEvent/respondWith

In all current engines.

Firefox44+Safari11.1+Chrome42+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

FetchEvent/resultingClientId

In all current engines.

Firefox65+Safari16+Chrome72+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile50+
✔MDN

FetchEvent

In all current engines.

Firefox44+Safari11.1+Chrome40+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

NavigationPreloadManager/disable

In all current engines.

Firefox99+Safari15.4+Chrome59+
Opera?Edge79+
Edge (Legacy)18IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

NavigationPreloadManager/enable

In all current engines.

Firefox99+Safari15.4+Chrome59+
Opera?Edge79+
Edge (Legacy)18IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

NavigationPreloadManager/getState

In all current engines.

Firefox99+Safari15.4+Chrome59+
Opera?Edge79+
Edge (Legacy)18IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

NavigationPreloadManager/setHeaderValue

In all current engines.

Firefox99+Safari15.4+Chrome59+
Opera?Edge79+
Edge (Legacy)18IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

NavigationPreloadManager

In all current engines.

Firefox99+Safari15.4+Chrome59+
Opera?Edge79+
Edge (Legacy)18IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

Navigator/serviceWorker

In all current engines.

Firefox44+Safari11.1+Chrome40+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

ServiceWorker/postMessage

In all current engines.

Firefox44+Safari11.1+Chrome40+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

ServiceWorker/postMessage

In all current engines.

Firefox44+Safari11.1+Chrome40+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

ServiceWorker/scriptURL

In all current engines.

Firefox44+Safari11.1+Chrome40+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

ServiceWorker/state

In all current engines.

Firefox44+Safari11.1+Chrome40+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

ServiceWorker/statechange_event

In all current engines.

Firefox44+Safari11.1+Chrome40+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

ServiceWorker

In all current engines.

Firefox44+Safari11.1+Chrome40+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

ServiceWorkerContainer/controller

In all current engines.

Firefox44+Safari11.1+Chrome40+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

ServiceWorkerContainer/controllerchange_event

In all current engines.

Firefox44+Safari11.1+Chrome40+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

ServiceWorkerContainer/getRegistration

In all current engines.

Firefox44+Safari11.1+Chrome40+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

ServiceWorkerContainer/getRegistrations

In all current engines.

Firefox44+Safari11.1+Chrome45+
Opera27+Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView40+Samsung Internet4.0+Opera Mobile27+
✔MDN

ServiceWorkerContainer/message_event

In all current engines.

Firefox44+Safari11.1+Chrome40+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

ServiceWorkerContainer/ready

In all current engines.

Firefox44+Safari11.1+Chrome40+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

ServiceWorkerContainer/register

In all current engines.

Firefox44+Safari11.1+Chrome40+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

ServiceWorkerContainer/startMessages

In all current engines.

Firefox64+Safari11.1+Chrome74+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile50+
✔MDN

ServiceWorkerContainer

In all current engines.

Firefox44+Safari11.1+Chrome40+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

ServiceWorkerGlobalScope/activate_event

In all current engines.

Firefox44+Safari11.1+Chrome40+
Opera24+Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile24+
✔MDN

ServiceWorkerGlobalScope/activate_event

In all current engines.

Firefox44+Safari11.1+Chrome40+
Opera24+Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile24+
✔MDN

ServiceWorkerGlobalScope/clients

In all current engines.

Firefox44+Safari11.1+Chrome40+
Opera24+Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile24+
✔MDN

ServiceWorkerGlobalScope/fetch_event

In all current engines.

Firefox44+Safari11.1+Chrome40+
Opera24+Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile24+
✔MDN

ServiceWorkerGlobalScope/install_event

In all current engines.

Firefox44+Safari11.1+Chrome40+
Opera24+Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile24+
✔MDN

ServiceWorkerGlobalScope/message_event

In all current engines.

Firefox44+Safari11.1+Chrome40+
Opera24+Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile24+
✔MDN

ServiceWorkerGlobalScope/message_event

In all current engines.

Firefox44+Safari11.1+Chrome40+
Opera24+Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile24+
✔MDN

ServiceWorkerGlobalScope/registration

In all current engines.

Firefox44+Safari11.1+Chrome42+
Opera26+Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile26+
✔MDN

ServiceWorkerGlobalScope/skipWaiting

In all current engines.

Firefox44+Safari11.1+Chrome41+
Opera25+Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile25+
✔MDN

ServiceWorkerGlobalScope

In all current engines.

Firefox44+Safari11.1+Chrome40+
Opera24+Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile24+
✔MDN

ServiceWorkerRegistration/active

In all current engines.

Firefox44+Safari11.1+Chrome40+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

ServiceWorkerRegistration/installing

In all current engines.

Firefox44+Safari11.1+Chrome40+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

ServiceWorkerRegistration/navigationPreload

In all current engines.

Firefox99+Safari15.4+Chrome59+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet4.0+Opera Mobile?
✔MDN

ServiceWorkerRegistration/scope

In all current engines.

Firefox44+Safari11.1+Chrome40+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

ServiceWorkerRegistration/unregister

In all current engines.

Firefox44+Safari11.1+Chrome40+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

ServiceWorkerRegistration/update

In all current engines.

Firefox44+Safari11.1+Chrome45+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet4.0+Opera Mobile?
✔MDN

ServiceWorkerRegistration/updatefound_event

In all current engines.

Firefox44+Safari11.1+Chrome40+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

ServiceWorkerRegistration/updateViaCache

In all current engines.

Firefox57+Safari11.1+Chrome68+
Opera?Edge79+
Edge (Legacy)18IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

ServiceWorkerRegistration/waiting

In all current engines.

Firefox44+Safari11.1+Chrome40+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

ServiceWorkerRegistration

In all current engines.

Firefox44+Safari11.1+Chrome40+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

WindowClient/focus

In all current engines.

Firefox44+Safari11.1+Chrome42+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

WindowClient/focused

In all current engines.

Firefox44+Safari11.1+Chrome42+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

WindowClient/navigate

In all current engines.

Firefox50+Safari16+Chrome49+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView42+Samsung Internet4.0+Opera Mobile?
✔MDN

WindowClient/visibilityState

In all current engines.

Firefox44+Safari11.1+Chrome42+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

WindowClient

In all current engines.

Firefox44+Safari11.1+Chrome42+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

caches

In all current engines.

Firefox41+Safari11.1+Chrome40+
Opera?Edge79+
Edge (Legacy)16+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

Headers/Service-Worker-Navigation-Preload

In all current engines.

Firefoxpreview+Safari15.4+Chrome59+
Opera?Edge79+
Edge (Legacy)18IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?