서비스 워커

W3C 후보 권고안 초안,

이 문서에 대한 추가 정보
이 버전:
https://www.w3.org/TR/2025/CRD-service-workers-20250306/
최신 공개 버전:
https://www.w3.org/TR/service-workers/
편집자 초안:
https://w3c.github.io/ServiceWorker/
변경 이력:
https://www.w3.org/standards/history/service-workers/
구현 보고서:
https://wpt.fyi/service-workers
피드백:
GitHub
명세 내 인라인
편집자:
(Microsoft)
(Google)
이전 편집자:
(Google)
(Google)
(Microsoft, 2018년 4월까지 삼성 대표)
(Google)
테스트:
web-platform-tests service-workers/ (진행 중 작업)

요약

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

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

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

이 문서의 상태

이 섹션은 이 문서가 발행된 시점의 상태를 설명합니다. 현재 W3C 발행물 목록과 이 기술 보고서의 최신 개정판은 W3C 기술 보고서 색인 https://www.w3.org/TR/에서 확인할 수 있습니다.

이 문서는 웹 애플리케이션 워킹 그룹에서 권고안 트랙을 사용하여 후보 권고안 초안으로 발행되었습니다.

이 명세에 대한 피드백과 의견을 환영합니다. 버그를 등록하거나, public-webapps@w3.org (구독, 아카이브)로 [service-workers]를 이메일 제목의 시작에 포함하여 의견을 보내주세요.

후보 권고안으로 발행되었다고 해서 W3C 및 그 회원의 지지를 의미하지는 않습니다. 후보 권고안 초안은 워킹 그룹이 이후의 후보 권고안 스냅샷에 포함하려는 이전 후보 권고안의 변경사항을 통합합니다.

이 문서는 초안으로, 언제든지 업데이트, 대체, 또는 폐기될 수 있습니다. 진행 중인 작업이 아닌 다른 용도로 이 문서를 인용하는 것은 부적절합니다.

이 문서는 W3C 특허 정책에 따라 운영되는 그룹에서 제작되었습니다. W3C공개 특허 공개 목록을 관리하며, 해당 그룹의 결과물과 관련하여 특허 공개가 이루어진 경우 해당 페이지에서 확인할 수 있습니다. 그 페이지에는 특허 공개 방법에 대한 안내도 포함되어 있습니다. 특정 특허에 실제로 관련된 정보를 알고 있는 개인은 W3C 특허 정책 6절에 따라 정보를 공개해야 합니다.

이 문서는 2023년 11월 3일 W3C 프로세스 문서의 적용을 받습니다.

1. 동기

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

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

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

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

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

서비스 워커는 문서가 아니라 이벤트와의 관계에 의해 시작되고 유지됩니다. 이 설계는 공유 워커Chrome 백그라운드 페이지에 대한 개발자 및 벤더의 경험에서 많은 부분을 차용했습니다. 이러한 시스템에서 얻은 주요 교훈은 백그라운드 처리 컨텍스트의 실행을 시간 제한해야 한다는 필요성입니다. 이는 자원을 절약하고, 백그라운드 컨텍스트의 손실 및 재시작이 개발자의 주요 고려 대상이 되도록 하기 위함입니다. 그 결과, 서비스 워커는 Chrome 이벤트 페이지(Background Pages의 후속작)와 매우 유사합니다. 서비스 워커는 사용자 에이전트가 문서를 첨부하지 않고도 시작할 수 있으며, 사용자 에이전트가 거의 언제든지 종료할 수 있습니다. 개념적으로, 서비스 워커는 문서에서 메시지를 처리하지 않고도 시작, 이벤트 처리, 종료가 가능한 공유 워커로 생각할 수 있습니다. 개발자들은 서비스 워커가 초당 여러 번 시작되고 종료될 수 있다는 점을 항상 염두에 두어야 합니다.

서비스 워커는 출처에서 실행되는 범용, 이벤트 기반, 시간 제한된 스크립트 컨텍스트입니다. 이러한 특성 덕분에 푸시 알림 처리, 백그라운드 데이터 동기화, 다른 출처의 리소스 요청 응답, 계산 비용이 큰 데이터(예: 위치정보나 자이로센서) 중앙 업데이트 등 특정 문서의 컨텍스트보다 오래 지속될 수 있는 다양한 런타임 서비스의 자연스러운 엔드포인트가 됩니다.

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를 통해 후에 노출되는 특정 시점을 표시합니다.

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

시작 시간

DOMHighResTimeStamp 타입, 초기값은 0입니다.

fetch 이벤트 디스패치 시간

DOMHighResTimeStamp 타입, 초기값은 0입니다.

2.3. 서비스 워커 등록

서비스 워커 등록scope url, storage key, 서비스 워커 집합(서비스 워커), installing worker, waiting worker, active worker의 튜플입니다. 사용자 에이전트는 서비스 워커 등록을 단일 출처에 여러 개 활성화할 수 있습니다. 단 scope url이 서로 달라야 합니다. 동일한 scope 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 sourcehandle functional event task source입니다.) 사용자 에이전트는 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. clientdiscarded flag를 설정합니다.

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

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

window client서비스 워커 클라이언트global objectWindow 객체인 경우입니다.

dedicated worker client서비스 워커 클라이언트global objectDedicatedWorkerGlobalScope 객체인 경우입니다.

shared worker client서비스 워커 클라이언트global objectSharedWorkerGlobalScope 객체인 경우입니다.

worker clientdedicated 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 documentoriginopaque origin이면, window clientactive service worker는 null로 설정합니다. 그렇지 않으면, 생성자 document서비스 워커 클라이언트active service worker로 설정합니다.

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

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

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

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

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

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

worker client가 생성될 때:

fetchHTTP fetch를 통해 라우팅된다면, worker clientactive service worker서비스 워커 등록 매칭의 결과로 설정합니다. 그렇지 않고 worker clientoriginopaque origin이거나, requestURLblob URL이고 worker clientorigin동일하지 않다면, originowner set의 마지막 worker clientglobal objectowner set과 동일하지 않다면, worker clientactive service worker는 null로 설정합니다. 그렇지 않으면, environment settings object의 마지막 owner setworker clientglobal objectowner setactive service worker로 설정합니다.

참고: Window clientworker clientdata: URL을 사용하면, 해당 active service worker 값은 null이 되며, 이는 originopaque origin이기 때문입니다. Window clientworker clientblob URL을 사용하면, 생성자 document 또는 소유자의 active service worker를 상속받을 수 있습니다. 하지만 requestorigin이 생성자 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 objectservice worker object map을 가집니다. 이는 으로, 서비스 워커이고, ServiceWorker 객체입니다.

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

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

    1. serviceWorkerObjenvironmentRealm에서 생성된 새로운 ServiceWorker 객체로 하고, serviceWorker와 연관시킨다.

    2. serviceWorkerObjstate 값을 serviceWorkerstate로 설정한다.

    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)messageoptions로 호출한다.

3.1.5. postMessage(message, options)

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

  1. serviceWorker서비스 워커로 한다. 이는 this로 표현됨.

  2. incumbentSettingsincumbent settings object로 한다.

  3. incumbentGlobalincumbentSettingsglobal object로 한다.

  4. serializeWithTransferResultStructuredSerializeWithTransfer(message, options["transfer"])로 한다. 예외가 발생하면 다시 던진다.

  5. "message"와 serviceWorkerShould Skip Event 알고리즘을 실행한 결과가 true라면 return 한다.

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

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

    2. 작업 큐에 추가DOM 조작 작업 소스에서 다음 단계로 실행:

      1. sourceincumbentGlobal의 타입에 따라 결정:

        ServiceWorkerGlobalScope
        incumbentGlobalservice workerserviceWorkerglobal objectrelevant settings object에서 service worker 객체 얻기로 반환.
        Window
        incumbentGlobalrelevant settings object를 나타내는 새로운 WindowClient 객체.
        그 외
        incumbentGlobal의 연관된 워커를 나타내는 새로운 Client 객체.
      2. originincumbentSettingsorigin 직렬화 값으로 한다.

      3. destinationserviceWorker와 연관된 ServiceWorkerGlobalScope 객체로 한다.

      4. deserializeRecordStructuredDeserializeWithTransfer(serializeWithTransferResult, destinationRealm)로 한다.

        이 과정에서 예외가 발생하면, e이벤트 생성으로 하고, 이름은 messageerror, ExtendableMessageEvent 사용, origin 속성은 origin, source 속성은 source로 초기화.

      5. 그 외에는:

        1. messageClonedeserializeRecord.[[Deserialized]]로 한다.

        2. newPortsfrozen array로, deserializeRecord.[[TransferredValues]]에 포함된 모든 MessagePort 객체를 순서대로 포함.

        3. e이벤트 생성으로 하고, 이름은 message, ExtendableMessageEvent 사용, origin 속성은 origin, source 속성은 source, data 속성은 messageClone, ports 속성은 newPorts로 초기화.

      6. edestination에서 디스패치 한다.

      7. 서비스 워커 확장 이벤트 집합 업데이트serviceWorkere로 호출한다.

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<undefined> 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. objectMapenvironment서비스 워커 등록 객체 맵으로 한다.

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

    1. registrationObjectenvironmentRealm에서 생성된 새로운 ServiceWorkerRegistration 객체로 한다.

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

    3. registrationObjectinstalling 속성을 null로 설정한다.

    4. registrationObjectwaiting 속성을 null로 설정한다.

    5. registrationObjectactive 속성을 null로 설정한다.

    6. registrationinstalling worker가 null이 아니면, registrationObjectinstalling 속성을 registrationinstalling workerenvironment에서 서비스 워커 객체 얻기로 반환한 값으로 설정한다.

    7. registrationwaiting worker가 null이 아니면, registrationObjectwaiting 속성을 registrationwaiting workerenvironment에서 서비스 워커 객체 얻기로 반환한 값으로 설정한다.

    8. registrationactive worker가 null이 아니면, registrationObjectactive 속성을 registrationactive workerenvironment에서 서비스 워커 객체 얻기로 반환한 값으로 설정한다.

    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관련 글로벌 객체 globalObjectServiceWorkerGlobalScope 객체이고, globalObject에 연관된 서비스 워커상태가 "installing"이면, "InvalidStateError" DOMException으로 거부된 프라미스를 반환하고 단계를 중단한다.

  5. promise프라미스로 한다.

  6. job작업 생성 알고리즘을 update, registrationstorage key, registrationscope url, newestWorkerscript url, promise, this관련 settings object를 인자로 실행한 결과로 한다.

  7. jobworker typenewestWorkertype으로 설정한다.

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

  9. promise를 반환한다.

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

unregister() 메서드 단계:

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

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

  3. job작업 생성 알고리즘을 unregister, registrationstorage key, registrationscope 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 objectNavigator 객체 또는 WorkerNavigator 객체와 연관된 것이다.

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

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

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

  1. clientthis서비스 워커 클라이언트로 한다.

  2. clientactive service worker 값이 null이면, null을 반환한다.

  3. clientactive service worker서비스 워커 객체 얻기로 얻은 값을 thissettings object에서 반환한다.

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

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

  1. thisready promise가 null이면, thisready promise새 프라미스로 설정한다.

  2. readyPromisethisready promise로 한다.

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

    1. clientthis서비스 워커 클라이언트로 한다.

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

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

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

  4. readyPromise를 반환한다.

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

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

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

  1. p프라미스로 한다.

  2. scriptURLTrustedScriptURL, this관련 글로벌 객체, scriptURL, "ServiceWorkerContainer register", "script"로 Get Trusted Type compliant string을 실행한 결과로 한다.

  3. clientthis서비스 워커 클라이언트로 한다.

  4. scriptURL파싱thissettings objectAPI base URL로 실행한 결과로 한다.

  5. scopeURL을 null로 한다.

  6. options["scope"] 값이 존재하면, scopeURL파싱options["scope"] 와 thissettings objectAPI base URL로 실행한 결과로 한다.

  7. Start RegisterscopeURL, scriptURL, p, client, clientcreation URL, options["type"], options["updateViaCache"]로 실행한다.

  8. p를 반환한다.

getRegistration(clientURL) 메서드 단계:

  1. clientthis서비스 워커 클라이언트로 한다.

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

  3. clientURL파싱clientURLthissettings objectAPI base URL로 실행한 결과로 한다.

  4. clientURL이 실패면, promise를 TypeError로 reject해서 반환한다.

  5. clientURLfragment를 null로 설정한다.

  6. clientURLoriginclientorigin과 다르면, promise를 "SecurityError" DOMException으로 reject해서 반환한다.

  7. promise새 프라미스로 한다.

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

    1. registration서비스 워커 등록 매칭storage keyclientURL을 인자로 실행한 결과로 한다.

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

    3. promise서비스 워커 등록 객체 얻기registrationpromisesettings object에서 반환한 값으로 resolve한다.

  9. promise를 반환한다.

getRegistrations() 메서드 단계:

  1. clientthis서비스 워커 클라이언트로 한다.

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

  3. promise새 프라미스로 한다.

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

    1. registrations새 리스트로 한다.

    2. (storage key, scope) → registration에 대해 registration map에서:

      1. storage keyclient storage key같으면, registrations에 registration 추가.

    3. 작업 큐에 추가promisesettings objectresponsible event loop에서 DOM manipulation 작업 소스로 다음 단계를 실행:

      1. registrationObjects새 리스트로 한다.

      2. registration에 대해 registrations에서:

        1. registrationObj서비스 워커 등록 객체 얻기로 registration을 promise의 settings object에서 반환한 값으로 한다.

        2. registrationObj를 registrationObjects에 추가.

      3. promiseregistrationObjects의 frozen array로 resolve한다. (promise의 Realm에서)

  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 Event 서비스 워커 클라이언트서비스 워커로부터 메시지를 받을 때. postMessage(message, options) 참고.
messageerror Event 서비스 워커 클라이언트서비스 워커로부터 역직렬화할 수 없는 메시지를 받을 때. 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. registrationthis의 연관된 서비스 워커 등록으로 설정한다.

    2. registration활성 워커가 null이면, "InvalidStateError" DOMException으로 promise를 거부하고, 이 단계들을 중단한다.

    3. registrationnavigation preload enabled flag를 설정한다.

    4. promise를 undefined로 해결한다.

  3. promise를 반환한다.

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

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

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

    1. registrationthis의 연관된 서비스 워커 등록으로 설정한다.

    2. registration활성 워커가 null이면, "InvalidStateError" DOMException으로 promise를 거부하고, 이 단계들을 중단한다.

    3. registrationnavigation preload enabled flag를 해제한다.

    4. promise를 undefined로 해결한다.

  3. promise를 반환한다.

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

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

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

    1. registrationthis의 연관된 서비스 워커 등록으로 설정한다.

    2. registration활성 워커가 null이면, "InvalidStateError" DOMException으로 promise를 거부하고, 이 단계들을 중단한다.

    3. registrationnavigation preload header valuevalue로 설정한다.

    4. promise를 undefined로 해결한다.

  3. promise를 반환한다.

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

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

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

    1. registrationthis의 연관된 서비스 워커 등록으로 설정한다.

    2. state를 새로운 NavigationPreloadState 딕셔너리로 설정한다.

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

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

    5. promisestate로 해결한다.

  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으로, keyrequest이고 valuerace response이다.

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

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

4.1.1. clients

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

4.1.2. registration

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

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로 resolve 한다.

  3. promise를 반환한다.

4.1.5. 이벤트 핸들러

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

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

4.2. 클라이언트

[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 객체는 가시성 상태와 연관되어 있는데, 이는 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. clientthis서비스 워커 클라이언트로 한다.

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

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

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

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

  3. 그 외의 경우:

    1. "window" 를 반환한다.

4.2.5. postMessage(message, transfer)

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

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

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

4.2.6. postMessage(message, options)

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

  1. contextObjectthis로 한다.

  2. sourceSettingscontextObject관련 설정 객체로 한다.

  3. serializeWithTransferResultStructuredSerializeWithTransfer(message, options["transfer"])로 한다. 예외가 발생하면 다시 던진다.

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

    1. targetClient를 null로 한다.

    2. 서비스 워커 클라이언트 client에 대해:

      1. 만약 clientcontextObject서비스 워커 클라이언트와 같다면, targetClientclient로 지정하고 반복을 중단한다.

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

    4. destination을 다음과 같이 한다: ServiceWorkerContainer 객체이며, 연관된 서비스 워커 클라이언트targetClient인 것이다.

    5. destination클라이언트 메시지 큐에 다음 단계들을 실행하는 태스크를 추가한다:

      1. origin설정 객체의 origin을 문자열로 변환한 값으로 한다.

      2. source서비스 워커 객체를 얻는 것의 결과로 한다. contextObject관련 글로벌 객체서비스 워커targetClient에서 나타내는 것이다.

      3. deserializeRecordStructuredDeserializeWithTransfer(serializeWithTransferResult, destination관련 Realm)로 한다.

        이 과정에서 예외가 발생하면, 예외를 잡아 messageerror 이벤트를 발생시키고, messageerror 이벤트를 destination에서 MessageEvent 객체로 사용하여 origin 속성은 origin으로, source 속성은 source로 초기화하고, 이 단계들을 중단한다.

      4. messageClonedeserializeRecord.[[Deserialized]]로 한다.

      5. newPortsfrozen array로 새로 만들고, deserializeRecord.[[TransferredValues]]에 있는 모든 MessagePort 객체를 포함한다(있다면).

      6. message 이벤트를 dispatch한다. message 이름으로 destination에서 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일시적 활성화가 없는 경우, "InvalidAccessError" DOMException으로 거부된 promise를 반환한다.

  2. serviceWorkerEventLoop주변 에이전트이벤트 루프로 한다.

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

  4. 태스크를 큐에 추가하여, this가 연관된 서비스 워커 클라이언트책임 이벤트 루프에서 사용자 상호작용 태스크 소스를 사용하여 다음 단계들을 실행한다:

    1. 포커싱 단계this브라우징 컨텍스트로 실행한다.

    2. frameTypeGet Frame Typethis브라우징 컨텍스트로 실행한 결과로 한다.

    3. visibilityStatethis브라우징 컨텍스트active documentvisibilityState 속성 값으로 한다.

    4. focusStatehas focus 단계this브라우징 컨텍스트active document로 실행한 결과로 한다.

    5. ancestorOriginsListthis브라우징 컨텍스트active document관련 글로벌 객체Location 객체의 조상 출처 목록의 연관된 목록으로 한다.

    6. 태스크를 큐에 추가하여, serviceWorkerEventLoop에서 DOM 조작 태스크 소스를 사용하여 다음 단계들을 실행한다:

      1. windowClientCreate Window Clientthis가 연관된 서비스 워커 클라이언트, frameType, visibilityState, focusState, ancestorOriginsList와 함께 실행한 결과로 한다.

      2. windowClient포커스 상태가 true라면, promisewindowClient로 resolve한다.

      3. 그 외에는 promiseTypeError로 reject한다.

  5. promise를 반환한다.

4.2.11. navigate(url)

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

  1. url파싱하여 얻은 값을 this관련 설정 객체API 기준 URL로 한다.

  2. url이 실패라면 TypeError로 거부된 promise를 반환한다.

  3. urlabout:blank라면 TypeError로 거부된 promise를 반환한다.

  4. this가 연관된 서비스 워커 클라이언트활성 서비스 워커this관련 글로벌 객체서비스 워커가 아니라면, TypeError로 거부된 promise를 반환한다.

  5. serviceWorkerEventLoop현재 글로벌 객체이벤트 루프로 한다.

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

  7. 태스크를 큐에 추가하여, this가 연관된 서비스 워커 클라이언트책임 이벤트 루프에서 사용자 상호작용 태스크 소스를 사용하여 다음 단계들을 실행한다:

    1. browsingContextthis브라우징 컨텍스트로 한다.

    2. browsingContext연관된 문서완전히 활성화되어 있지 않다면, 태스크를 큐에 추가하여 promiseTypeError로 reject하고, serviceWorkerEventLoop에서 DOM 조작 태스크 소스를 사용하며, 이 단계들을 중단한다.

    3. HandleNavigate: 브라우징 컨텍스트를 url로 네비게이트한다. browsingContext연관된 문서를 사용하며, exceptionsEnabled는 true로 한다.

    4. HandleNavigate 단계에서 예외가 발생하면, 태스크를 큐에 추가하여 promise를 해당 예외로 reject하고, serviceWorkerEventLoop에서 DOM 조작 태스크 소스를 사용하며, 이 단계들을 중단한다.

    5. frameTypeGet Frame TypebrowsingContext로 실행한 결과로 한다.

    6. visibilityStatebrowsingContextactive documentvisibilityState 속성 값으로 한다.

    7. focusStatehas focus 단계browsingContextactive document로 실행한 결과로 한다.

    8. ancestorOriginsListbrowsingContextactive document관련 글로벌 객체Location 객체의 조상 출처 목록의 연관된 목록으로 한다.

    9. 태스크를 큐에 추가하여, serviceWorkerEventLoop에서 DOM 조작 태스크 소스를 사용하여 다음 단계들을 실행한다:

      1. browsingContextWindow 객체의 환경 설정 객체생성 URLorigin동일하지 않다면, 서비스 워커origin과 다르다면, promise를 null로 resolve하고 이 단계들을 중단한다.

      2. windowClientCreate Window Clientthis가 연관된 서비스 워커 클라이언트, frameType, visibilityState, focusState, ancestorOriginsList와 함께 실행한 결과로 한다.

      3. promisewindowClient로 resolve한다.

  8. promise를 반환한다.

4.3. Clients

[Exposed=ServiceWorker]
interface Clients {
  // 반환되는 객체는 항상 새로운 인스턴스이다
  [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. 서비스 워커 클라이언트 client에 대해, 스토리지 키를 얻기client에 대해 실행한 결과가 연관된 서비스 워커등록 객체스토리지 키와 같은 경우:

      1. clientidid와 다르면 다음 반복을 한다.

      2. client실행 준비 플래그 가 설정되거나 client폐기 플래그가 설정될 때까지 대기한다.

      3. client실행 준비 플래그 가 설정되어 있다면, Resolve Get Client Promiseclientpromise를 인수로 호출하고 이 단계들을 중단한다.

    2. promise를 undefined로 resolve한다.

  3. promise를 반환한다.

4.3.2. matchAll(options)

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

  1. promise새로운 promise로 한다.

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

    1. targetClients를 새로운 리스트로 한다.

    2. 서비스 워커 클라이언트 client에 대해, 스토리지 키를 얻기client에 대해 실행한 결과가 연관된 서비스 워커등록 객체스토리지 키와 같은 경우:

      1. client실행 준비 플래그가 설정되어 있지 않거나 client폐기 플래그가 설정되어 있다면 다음 반복을 한다.

      2. client보안 컨텍스트가 아니라면 다음 반복을 한다.

      3. options["includeUncontrolled"] 가 false이고, client활성 서비스 워커 가 연관된 서비스 워커가 아니라면, 다음 반복을 한다.

      4. clienttargetClients에 추가한다.

    3. matchedWindowData를 새로운 리스트로 한다.

    4. matchedClients를 새로운 리스트로 한다.

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

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

        1. windowData를 «[ "client" → client, "ancestorOriginsList" → 새로운 리스트 ]»로 한다.

        2. browsingContext를 null로 한다.

        3. isClientEnumerable를 true로 한다.

        4. client환경 설정 객체라면, browsingContextclient글로벌 객체브라우징 컨텍스트로 한다.

        5. 그 외의 경우 browsingContextclient타겟 브라우징 컨텍스트로 한다.

        6. 태스크를 큐에 추가하여, browsingContext이벤트 루프에서 사용자 상호작용 태스크 소스를 사용하여 다음 하위 단계들을 실행한다:

          1. browsingContext폐기(discarded)되었다면, isClientEnumerable를 false로 하고 이 단계들을 중단한다.

          2. client가 window client이고 client연관된 문서browsingContextactive document가 아니라면, isClientEnumerable를 false로 하고 이 단계들을 중단한다.

          3. windowData["frameType"]에 Get Frame TypebrowsingContext로 실행한 결과를 할당한다.

          4. windowData["visibilityState"] 에 browsingContextactive documentvisibilityState 속성 값을 할당한다.

          5. windowData["focusState"]에 has focus 단계browsingContextactive document로 실행한 결과를 할당한다.

          6. clientwindow client라면, windowData["ancestorOriginsList"] 에 browsingContextactive document글로벌 객체Location 객체의 조상 출처 목록의 연관된 목록을 할당한다.

        7. 태스크가 실행될 때까지 대기한다.

          참고: 대기는 블로킹 대기이지만, 구현체는 상태가 깨지지 않는 한 반복을 병렬로 실행할 수 있다.

        8. isClientEnumerable가 true라면:

          1. windowDatamatchedWindowData에 추가한다.

      2. 그 외에 options["type"] 가 "worker" 또는 "all"이고 clientdedicated worker client이거나, options["type"] 가 "sharedworker" 또는 "all"이고 clientshared worker client라면, 다음을 실행한다:

        1. clientmatchedClients에 추가한다.

    6. 태스크를 큐에 추가하여, promise관련 설정 객체책임 이벤트 루프에서 DOM 조작 태스크 소스를 사용하여 다음 단계들을 실행한다:

      1. clientObjects를 새로운 리스트로 한다.

      2. windowData에 대해 matchedWindowData에서:

        1. windowClientCreate Window Client 알고리즘을 windowData["client"], windowData["frameType"], windowData["visibilityState"], windowData["focusState"], windowData["ancestorOriginsList"]를 인수로 실행한 결과로 한다.

        2. windowClientclientObjects에 추가한다.

      3. client에 대해 matchedClients에서:

        1. clientObjectCreate Client 알고리즘을 client를 인수로 실행한 결과로 한다.

        2. clientObjectclientObjects에 추가한다.

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

        참고: Window client가 항상 worker client보다 앞에 온다.

      5. promisefrozen arrayclientObjects를 resolve한다. relevant Realm에서 실행한다.

  3. promise를 반환한다.

4.3.3. openWindow(url)

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

  1. url파싱하여 얻은 값을 this관련 설정 객체API 기준 URL로 한다.

  2. url이 실패라면 TypeError로 거부된 promise를 반환한다.

  3. urlabout:blank라면 TypeError로 거부된 promise를 반환한다.

  4. 출처 내에 Window일시적 활성화가 없는 경우, "InvalidAccessError" DOMException으로 거부된 promise를 반환한다.

  5. serviceWorkerEventLoop현재 글로벌 객체이벤트 루프로 한다.

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

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

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

    2. 태스크를 큐에 추가하여, newContextWindow 객체의 환경 설정 객체책임 이벤트 루프에서 사용자 상호작용 태스크 소스를 사용하여 다음 단계들을 실행한다:

      1. HandleNavigate: newContext를 url로 네비게이트한다. exceptionsEnabled는 true, historyHandling "replace"로 한다.

      2. HandleNavigate 단계에서 예외가 발생하면, 태스크를 큐에 추가하여 promise를 해당 예외로 reject하고, serviceWorkerEventLoop에서 DOM 조작 태스크 소스를 사용하며, 이 단계들을 중단한다.

      3. frameTypeGet Frame TypenewContext로 실행한 결과로 한다.

      4. visibilityStatenewContextactive documentvisibilityState 속성 값으로 한다.

      5. focusStatehas focus 단계newContextactive document를 인수로 실행한 결과로 한다.

      6. ancestorOriginsListnewContextactive document글로벌 객체Location 객체의 조상 출처 목록의 연관된 목록으로 한다.

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

        1. 스토리지 키를 얻기newContextWindow 객체의 환경 설정 객체로 실행한 결과가 동일하지 않으면, 서비스 워커등록 객체스토리지 키와 같지 않으면, promise를 null로 resolve하고 이 단계들을 중단한다.

        2. clientCreate Window ClientnewContextWindow 객체의 환경 설정 객체, frameType, visibilityState, focusState, ancestorOriginsList를 인수로 실행한 결과로 한다.

        3. promiseclient로 resolve한다.

  8. promise를 반환한다.

4.3.4. claim()

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

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

  2. promise를 새로운 promise로 한다.

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

    1. 서비스 워커 클라이언트 client에 대해, 스토리지 키를 얻기client에 대해 실행한 결과가 동일하면, 서비스 워커등록 객체스토리지 키와 같은 경우:

      1. client실행 준비 플래그가 설정되어 있지 않거나 client폐기 플래그가 설정되어 있다면 다음 반복을 한다.

      2. client보안 컨텍스트가 아니라면 다음 반복을 한다.

      3. storage key스토리지 키를 얻기client에 대해 실행한 결과로 한다.

      4. registrationMatch Service Worker Registrationstorage keyclient생성 URL을 인수로 실행한 결과로 한다.

      5. registration서비스 워커등록 객체가 아니라면 다음 반복을 한다.

        참고: registration서비스 워커등록 객체등록 해제됨일 경우 null이다.

      6. client활성 서비스 워커서비스 워커가 아니라면 다음을 실행한다:

        1. Handle Service Worker Client Unloadclient를 인수로 호출한다.

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

        3. Notify Controller Change 알고리즘을 client를 인수로 실행한다.

    2. 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 {
  // 파생 이벤트의 향후 호환성을 위해 정의됨
};

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

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

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

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

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

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

4.4.1. event.waitUntil(f)

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

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

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

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

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

  3. promiseevent수명 연장 프라미스에 추가한다.

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

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

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

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

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

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

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

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

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

서비스 워커확장에서 이벤트 핸들러를 정의하는 경우, 자체 동작을 정의할 수 있으며, 수명 연장 프라미스가 작업 길이를 제안할 수 있고, 프라미스가 reject된 경우 작업 실패를 제안할 수 있다.

참고: 서비스 워커installing worker를 "installed"로 처리하는 것을 install 이벤트의 수명 연장 프라미스가 모두 성공적으로 resolve될 때까지 지연한다. (Install 알고리즘 단계 참고.) 프라미스 중 하나라도 reject되면 설치가 실패한다. 이는 서비스 워커가 의존하는 핵심 캐시가 모두 채워질 때까지 "installed"로 간주되지 않게 하는 데 주로 사용된다. 이와 마찬가지로, 서비스 워커active worker를 "activated"로 처리하는 것을 activate 이벤트의 수명 연장 프라미스가 모두 settle될 때까지 지연한다. (Activate 알고리즘 단계 참고.) 이는 서비스 워커가 데이터베이스 스키마를 업그레이드하고, 오래된 캐시 항목을 삭제할 때까지 기능성 이벤트가 active worker에 dispatch되지 않도록 하는 데 주로 사용된다.

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. rulesRouterRule 딕셔너리면, rules를 « rules »로 설정한다.

  2. serviceWorker현재 글로벌 객체서비스 워커로 한다.

  3. rules의 각 rule에 대해:

    1. 라우터 조건 검증 알고리즘을 rule["condition"] 및 serviceWorker로 실행한 결과가 false라면, TypeError로 reject된 promise를 반환한다.

    2. rule["source"]가 "fetch-event" 또는 "race-network-and-fetch-handler" 중 하나이고, serviceWorker처리할 이벤트 타입 집합fetch 이벤트가 포함되지 않으면, TypeError로 reject된 promise를 반환한다.

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

  5. 수명 연장 프라미스 추가 lifetimePromisethis에 추가한다.

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

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

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

    참고: 이 단계는 install 이벤트 실패를 방지하기 위해 lifetimePromise가 항상 이행되도록 한다.

  8. 다음 단계들을 [[service worker queue]]에 추가한다:

    1. allRulesserviceWorker라우터 규칙 목록의 복사본으로 한다.

    2. rules의 각 rule에 대해:

      1. ruleallRules에 추가한다.

    3. 라우터 등록 제한 체크allRules로 실행한 결과가 false라면, promiseTypeError로 reject한다.

    4. serviceWorker라우터 규칙 목록allRules로 설정한다.

    5. serviceWorkerEventLoop현재 글로벌 객체이벤트 루프로 한다.

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

      1. promise를 undefined로 resolve한다.

  9. 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 속성은 반드시 초기화된 값을 반환해야 한다. 이벤트가 생성될 때 해당 속성은 반드시 빈 문자열로 초기화되어야 한다.

4.6.4. event.resultingClientId

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

4.6.5. event.replacesClientId

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

4.6.6. event.handled

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

4.6.7. event.respondWith(r)

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

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

  1. eventthis로 한다.

  2. eventdispatch 플래그가 unset이면, "InvalidStateError" DOMExceptionthrow한다.

  3. eventrespondWith 진입 플래그가 설정되어 있으면, "InvalidStateError" DOMExceptionthrow한다.

  4. 수명 연장 프라미스 추가 revent에 추가한다.

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

  5. eventstop propagation 플래그stop immediate propagation 플래그를 설정한다.

  6. eventrespondWith 진입 플래그를 설정한다.

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

  8. targetRealmeventrelevant Realm으로 한다.

  9. r가 reject될 때:

    1. eventrespondWith 오류 플래그를 설정한다.

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

  10. r가 이행될 때 response로:

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

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

    2. 그 외에는:

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

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

      3. done을 false로 한다.

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

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

        1. readerreader 얻기responsebodystream에 대해 실행한 결과로 한다.

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

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

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

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

            3. potentialResponsebody infoencoded sizebytesbyte length만큼 증가시킨다.

            4. potentialResponsebody infodecoded sizebytesbyte length만큼 증가시킨다.

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

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

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

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

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

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

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

        6. newStreamReadableStream의 새 인스턴스로 만들고, set uppullAlgorithm pullAlgorithm, cancelAlgorithm cancelAlgorithm, highWaterMark highWaterMark, sizeAlgorithm sizeAlgorithmtargetRealm에서 실행한다.

        7. potentialResponsebody를, body의 새 인스턴스로 하고 그 streamnewStream으로 한다.

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

          1. newStreamerroreddone을 true로 한다.

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

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

            1. chunkbytes 처음부터의 부분 시퀀스로 한다.

            2. chunkbytes에서 제거한다.

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

            4. newStream에 enqueue한다. Uint8ArraytargetRealm에서 buffer를 감싼다.

        참고: 이 단계들은 responsebodystreampotentialResponse에 "파이프"하는 것과 동등한 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 = [];
};

서비스 워커extendable message 이벤트를 정의하여 이벤트의 수명을 확장할 수 있도록 합니다. message 이벤트의 경우, 서비스 워커ExtendableMessageEvent 인터페이스를 사용하며, 이 인터페이스는 ExtendableEvent 인터페이스를 확장합니다.

4.7.1. event.data

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

4.7.2. event.origin

origin 속성은 초기화된 값을 반환해야 합니다. 객체가 생성될 때 이 속성은 빈 문자열로 초기화되어야 합니다. 이 속성은 메시지를 보낸 origin을 나타내며, 서비스 워커 클라이언트의 origin입니다.

4.7.3. event.lastEventId

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

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 fetchHandle Fetchrequest와 함께 호출할 때 발생합니다. Handle Fetch를 수행하면 서비스 워커응답HTTP fetch에 반환합니다. 응답Response 객체로 표현되며, Cache 객체에서 가져오거나 self.fetch(input, init) 메서드를 통해 네트워크에서 직접 가져올 수 있습니다. (사용자 정의 Response 객체도 가능합니다.)
push PushEvent 기능적 (자세한 내용은 푸시 이벤트 발생를 참고하세요.)
notificationclick NotificationEvent 기능적 (자세한 내용은 알림 활성화를 참고하세요.)
notificationclose NotificationEvent 기능적 (자세한 내용은 알림 닫기를 참고하세요.)
sync SyncEvent 기능적 (자세한 내용은 Sync 이벤트 발생를 참고하세요.)
canmakepayment CanMakePaymentEvent 기능적 (자세한 내용은 CanMakePaymentEvent 처리를 참고하세요.)
paymentrequest PaymentRequestEvent 기능적 (자세한 내용은 PaymentRequestEvent 처리를 참고하세요.)
message ExtendableMessageEvent 레거시 메시지를 수신할 때 발생합니다.
messageerror MessageEvent 레거시 역직렬화할 수 없는 메시지를 수신할 때 발생합니다.

5. 캐시

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

5.1. 구성요소

request response list리스트이며, 각각 튜플로 구성되어 있고, 요청(request)과 응답(response)을 포함합니다.

relevant request response listthis가 나타내는 인스턴스입니다.

name to cache map순서가 있는 맵이며, 엔트리 (즉, request response list의 이름을 나타내는 문자열)와 (request response list)로 구성됩니다.

storage key는 연관된 name to cache map을 가집니다.

relevant name to cache mapname to cache map이며, storage key얻은 this의 연관된 글로벌 객체환경 설정 객체에 연결되어 있습니다.

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 operationstruct로 구성되며 다음을 포함합니다:

5.4.1. match(request, options)

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

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

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

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

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

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

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

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

      1. responses가 빈 배열이면,

        1. promise를 undefined로 resolve합니다.

      2. 그 외의 경우:

        1. promiseresponses의 첫 번째 요소로 resolve합니다.

  3. promise를 반환합니다.

5.4.2. matchAll(request, options)

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

  1. r을 null로 둡니다.

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

    1. requestRequest 객체라면:

      1. rrequestrequest를 설정합니다.

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

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

      1. rRequest 생성자에 request를 인자로 주어 생성한 결과의 관련 request를 설정합니다. 만약 예외가 발생하면, 해당 예외로 reject된 promise를 반환합니다.

  3. realmthis관련 realm으로 둡니다.

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

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

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

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

      1. requestResponserelevant request response list에서 반복하여:

        1. requestResponse의 response의 복사본을 responses에 추가합니다.

    3. 그렇지 않은 경우:

      1. requestResponsesQuery Cacheroptions를 전달하여 실행한 결과로 둡니다.

      2. requestResponserequestResponses에서 반복하여:

        1. requestResponse의 response의 복사본을 responses에 추가합니다.

    4. responseresponses에서 반복하여:

      1. responsetype이 "opaque"이고 cross-origin resource policy checkpromiserelevant settings objectorigin, promiserelevant settings object, "", responseinternal response가 blocked를 반환하면, promiseTypeError로 reject하고 해당 단계를 중단합니다.

    5. 작업을 큐에 추가하여, promiserelevant settings objectresponsible event loop에서 DOM manipulation task source로 다음 단계를 수행합니다:

      1. responseList리스트로 둡니다.

      2. responseresponses에서 반복하여:

        1. response와 연결된 새로운 Response 객체와, guard가 "immutable"인 새로운 Headers 객체를 responseList에 추가하세요.

      3. promisefrozen array생성responseList로, realm에서 resolve합니다.

  6. promise를 반환합니다.

5.4.3. add(request)

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

  1. requestsrequest만을 포함하는 배열로 둡니다.

  2. responseArrayPromiseaddAll(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. rrequestrequest로 둡니다.

    2. rurlscheme이 "http", "https"가 아니거나, rmethod가 `GET`이 아니면, TypeError로 reject된 promise를 반환합니다.

  4. fetchControllers리스트로 두고, fetch controller를 포함합니다.

  5. requests의 각 request에 대해:

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

    2. rurlscheme이 "http", "https"가 아니면:

      1. fetchControllerfetchControllers에서 반복하여, abort 합니다.

      2. TypeError로 reject된 promise를 반환합니다.

    3. rclientglobal objectServiceWorkerGlobalScope 객체라면, requestservice-workers mode를 "none"으로 설정합니다.

    4. rinitiator를 "fetch", destination을 "subresource"로 설정합니다.

    5. rrequestList에 추가합니다.

    6. responsePromise새로운 promise로 둡니다.

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

      • Append를 통해 fetching r의 결과를 추가합니다.

      • processResponse에서 response에 대해 다음을 실행합니다:

        1. responsetype이 "error"이거나, responsestatusok status가 아니거나 206이면, responsePromise를 TypeError로 reject합니다.

        2. 그 외에 responseheader listheader 이름이 `Vary`인 것이 있으면:

          1. fieldValues리스트로 두고, field-values에 해당하는 요소들을 포함합니다.

          2. fieldValuefieldValues에서 반복하여:

            1. fieldValue가 "*"에 매칭되면:

              1. responsePromise를 TypeError로 reject합니다.

              2. fetchControllerfetchControllers에서 반복하여 abort 합니다.

              3. 이 단계들을 중단합니다.

      • processResponseEndOfBody에서 response에 대해 다음을 실행합니다:

        1. responseaborted flag가 설정되어 있으면, responsePromise를 "AbortError" DOMException으로 reject하고 이 단계들을 중단합니다.

        2. responsePromiseresponse로 resolve합니다.

        참고: 응답의 body가 모두 수신되면 캐시 커밋이 허용됩니다.

    8. responsePromiseresponsePromises에 추가합니다.

  6. p모든 responsePromises를 기다리는 promise로 둡니다.

  7. reacting을 통해 p가 fulfill될 때, responses를 인자로 받아 다음 하위 단계를 수행합니다:

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

    2. index를 0으로 둡니다.

    3. responses의 각 response에 대해:

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

      2. operationtype을 "put"으로 설정합니다.

      3. operationrequestrequestList[index]로 설정합니다.

      4. operationresponseresponse로 설정합니다.

      5. Append를 통해 operationoperations에 추가합니다.

      6. index를 1 증가시킵니다.

    4. realmthis관련 realm으로 둡니다.

    5. cacheJobPromise새로운 promise로 둡니다.

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

      1. errorData를 null로 둡니다.

      2. Batch Cache Operationsoperations로 호출합니다. 이때 예외가 발생하면 errorData에 해당 예외를 설정합니다.

      3. 작업을 큐에 추가하여, cacheJobPromiserelevant settings objectresponsible event loop에서 DOM manipulation task source로 다음 하위 단계를 수행합니다:

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

        2. 그 외에는, cacheJobPromisenew exception으로 errorDatarealm을 인자로 하여 reject합니다.

    7. cacheJobPromise를 반환합니다.

5.4.5. put(request, response)

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

  1. innerRequest를 null로 둡니다.

  2. requestRequest 객체라면, innerRequestrequestrequest로 설정합니다.

  3. 그 외의 경우:

    1. requestObjRequest 생성자에 request를 인자로 하여 실행한 결과로 설정합니다. 만약 예외가 발생하면, 해당 예외로 reject된 promise를 반환합니다.

    2. innerRequestrequestObjrequest로 설정합니다.

  4. innerRequesturlscheme이 "http", "https"가 아니거나, innerRequestmethod가 `GET`이 아니면, TypeError로 reject된 promise를 반환합니다.

  5. innerResponseresponseresponse로 둡니다.

  6. innerResponsestatus206이면, TypeError로 reject된 promise를 반환합니다.

  7. innerResponseheader listheader 이름이 `Vary`인 것이 있으면:

    1. fieldValues리스트itemVary 헤더의 field-values에 해당하는 것으로 둡니다.

    2. fieldValuefieldValues에서 반복하여:

      1. fieldValue가 "*"에 매칭되면, TypeError로 reject된 promise를 반환합니다.

  8. innerResponsebodydisturbed 또는 locked 상태라면, TypeError로 reject된 promise를 반환합니다.

  9. clonedResponseinnerResponse의 복제본으로 둡니다.

  10. bodyReadPromiseundefined로 resolve된 promise로 둡니다.

  11. innerResponsebody가 null이 아니면, 다음 하위 단계를 실행합니다:

    1. streaminnerResponsebodystream으로 둡니다.

    2. readerstream에 대한 reader 얻기 결과로 둡니다.

    3. bodyReadPromisereader에서 모든 바이트 읽기 결과로 설정합니다.

    참고: 이는 innerResponsebodylocked가 되고, clonedResponse에 body 버퍼 복사본이 생긴다는 것을 보장합니다. 구현은 메모리 대신 디스크로 스트리밍하여 최적화할 수 있습니다.

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

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

  14. operationtype을 "put"으로 설정합니다.

  15. operationrequestinnerRequest로 설정합니다.

  16. operationresponseclonedResponse로 설정합니다.

  17. Append를 통해 operationoperations에 추가합니다.

  18. realmthis관련 realm으로 둡니다.

  19. bodyReadPromise가 fulfill될 때의 결과로:

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

    2. cacheJobPromise를 반환하고, 다음 단계들을 병렬로 수행합니다:

      1. errorData를 null로 둡니다.

      2. Batch Cache Operationsoperations에 대해 호출합니다. 만약 예외가 발생하면 errorData에 예외를 설정합니다.

      3. 작업을 큐에 추가하여, cacheJobPromiserelevant settings objectresponsible event loop에서 DOM manipulation task source로 다음 단계들을 수행합니다:

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

        2. 그 외에는, cacheJobPromisenew exception으로 errorDatarealm을 인자로 하여 reject합니다.

5.4.6. delete(request, options)

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

  1. r을 null로 둡니다.

  2. requestRequest 객체라면:

    1. rrequestrequest를 설정합니다.

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

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

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

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

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

  6. operationtype을 "delete"로 설정합니다.

  7. operationrequestr로 설정합니다.

  8. operationoptionsoptions로 설정합니다.

  9. Append를 통해 operationoperations에 추가합니다.

  10. realmthis관련 realm으로 둡니다.

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

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

    1. errorData를 null로 둡니다.

    2. requestResponsesBatch Cache Operationsoperations를 전달하여 실행한 결과로 둡니다. 이때 예외가 발생하면 errorData에 예외를 설정합니다.

    3. 작업을 큐에 추가하여, cacheJobPromiserelevant settings objectresponsible event loop에서 DOM manipulation task source로 다음 하위 단계를 수행합니다:

      1. errorData가 null이면:

        1. requestResponses비어있지 않으면, cacheJobPromise를 true로 resolve합니다.

        2. 그 외에는, cacheJobPromise를 false로 resolve합니다.

      2. 그 외에는, cacheJobPromisenew exception으로 errorDatarealm을 인자로 하여 reject합니다.

  13. cacheJobPromise를 반환합니다.

5.4.7. keys(request, options)

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

  1. r을 null로 둡니다.

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

    1. requestRequest 객체라면:

      1. rrequestrequest로 설정합니다.

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

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

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

  3. realmthis관련 realm으로 둡니다.

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

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

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

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

      1. requestResponserelevant request response list에서 반복하여:

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

    3. 그 외의 경우:

      1. requestResponsesQuery Cacheroptions를 전달하여 실행한 결과로 둡니다.

      2. requestResponserequestResponses에서 반복하여:

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

    4. 작업을 큐에 추가하여, promiserelevant settings objectresponsible event loop에서 DOM manipulation task source로 다음 단계를 수행합니다:

      1. requestList리스트로 둡니다.

      2. requestrequests에서 반복하여:

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

      3. promisefrozen 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, entriesvalues 메서드는 TC39의 비동기 반복에 대한 지속적인 논의에 따라 첫 번째 버전에서는 일부러 제외되었습니다.

사용자 에이전트는 CacheStorage 객체를 Window 객체 또는 WorkerGlobalScope 객체가 생성될 때 생성하여 해당 글로벌 객체에 연결해야 합니다.

CacheStorage 객체는 자신과 연관된 name to cache map을 나타내며, 해당 글로벌 객체환경 설정 객체origin에 기반합니다. 여러 문서와 워커에서 CacheStorage 인터페이스를 구현하는 별도의 객체들이 동시에 같은 name to cache map에 연결될 수 있습니다.

5.5.1. match(request, options)

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

  1. options["cacheName"] 존재하면:

    1. 새로운 promise promise를 반환하고, 다음 하위 단계들을 병렬로 실행합니다:

      1. cacheNamecacherelevant name to cache map에서 반복하여:

        1. options["cacheName"]가 cacheName과 일치하면:

          1. Cache 인터페이스의 match(request, options) 메서드 알고리즘을 requestoptions를 인자로 cache를 thisArgument로 하여 실행한 결과로 promise를 resolve합니다.

          2. 이 단계들을 중단합니다.

      2. promise를 undefined로 resolve합니다.

  2. 그 외의 경우:

    1. promiseundefined로 resolve된 promise로 둡니다.

    2. cacheNamecacherelevant name to cache map에서 반복하여:

      1. promise를 자신에 reacting한 결과로 두고, fulfillment handler에서 response를 인자로 다음을 수행합니다:

        1. response가 undefined가 아니면 response를 반환합니다.

        2. Cache 인터페이스의 match(request, options) 알고리즘을 requestoptions를 인자로 cache를 thisArgument로 하여 실행한 결과를 반환합니다.

    3. promise를 반환합니다.

5.5.2. has(cacheName)

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

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

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

    1. keyvaluerelevant name to cache map에서 반복하여:

      1. cacheNamekey와 일치하면, promise를 true로 resolve하고 이 단계들을 중단합니다.

    2. promise를 false로 resolve합니다.

  3. promise를 반환합니다.

5.5.3. open(cacheName)

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

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

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

    1. keyvaluerelevant name to cache map에서 반복하여:

      1. cacheNamekey와 일치하면:

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

        2. 이 단계들을 중단합니다.

    2. cache를 새로운 request response list로 둡니다.

    3. Set을 통해 relevant name to cache map[cacheName]에 cache를 저장합니다. 만약 캐시 쓰기 작업이 할당된 quota 제한을 초과하여 실패하면, promise를 "QuotaExceededError" DOMException으로 reject하고 이 단계들을 중단합니다.

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

  3. promise를 반환합니다.

5.5.4. delete(cacheName)

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

  1. promisehas(cacheName) 알고리즘을 cacheName으로 실행한 결과로 둡니다.

  2. promise가 fulfill될 때, fulfillment handler에서 cacheExists를 인자로 다음을 수행합니다:

    1. cacheExists가 false이면:

      1. false를 반환합니다.

    2. cacheJobPromise새로운 promise로 둡니다.

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

      1. Remove를 통해 relevant name to cache map[cacheName]을 제거합니다.

      2. cacheJobPromise를 true로 resolve합니다.

      참고: 이 단계 이후에도 기존 DOM 객체(즉, 현재 참조된 Cache, Request, Response 객체)는 계속 동작해야 합니다.

    4. cacheJobPromise를 반환합니다.

5.5.5. keys()

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

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

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

    1. cacheKeysrelevant name to cache map의 키를 얻은 결과로 둡니다.

      참고: 결과 ordered set에 있는 item들은 해당 엔트리가 name to cache map에 추가된 순서대로입니다.

    2. promisecacheKeys로 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. serviceWorkerrequestclient글로벌 객체서비스 워커로 둡니다.

  2. mapserviceWorker스크립트 리소스 맵으로 둡니다.

  3. urlrequesturl로 둡니다.

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

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

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

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

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

  6. registrationserviceWorker포함 서비스 워커 등록으로 둡니다.

  7. requestservice-workers mode를 "none"으로 설정합니다.

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

  9. responserequest에 대해 fetch한 결과로 둡니다.

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

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

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

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

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

  15. response를 반환합니다.

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

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

애플리케이션은 CDN이나 다른 오리진에서 가져온 항목을 캐시하는 경우가 많습니다. <script>, <img>, <video>, <link> 요소를 통해 많은 리소스를 직접 요청할 수 있습니다. 이런 종류의 런타임 협업이 오프라인에서 깨진다면 상당한 제약이 될 것입니다. 마찬가지로 적절한 CORS 헤더가 설정된 경우 fetch를 통해 다양한 오프-오리진 리소스를 요청할 수 있습니다. 서비스 워커캐시를 통해 오프-오리진 항목을 fetch 및 캐시할 수 있게 허용합니다. 단, 몇 가지 제한이 있습니다. 먼저, 동일 오리진 리소스는 Cache에서 Response 객체로 관리되고, 해당 response기본 필터된 응답입니다. 반면, 오프-오리진에서 저장되는 객체는 Response 객체로, 해당 responseCORS 필터된 응답 또는 불투명(opaque) 필터된 응답입니다. 이들은 event.respondWith(r) 메서드로 동일하게 전달할 수 있지만, 의미 있게 프로그래밍적으로 생성할 수는 없습니다. 이러한 제한은 플랫폼의 보안 불변성을 유지하기 위해 필요합니다. 캐시가 이런 객체를 저장할 수 있게 하여 애플리케이션이 대부분의 경우 아키텍처를 변경하지 않아도 되도록 합니다.

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. 프라이버시

서비스 워커등록 맵 (서비스 워커 등록 및 서비스 워커 등록서비스 워커), request response list, name to cache map (캐시용), 스크립트 리소스 맵 (스크립트 리소스용) 등 새로운 영구 저장소 기능을 도입합니다. 비인가 웹 추적 위협을 방지하기 위해, 이러한 영구 저장소는 사용자가 삭제를 원하는 경우 삭제되어야 하며, 모든 기존 사용자 제어 기능(예: 모든 영구 저장소 일괄 삭제)과 호환되어야 합니다.

7. 확장성

서비스 워커 명세는 다른 명세에서 확장할 수 있습니다.

7.1. Service Worker Registration에 바인딩된 API 정의

명세는 API를 서비스 워커 등록(service worker registration)에 바인딩하도록 partial interface 정의를 ServiceWorkerRegistration 인터페이스에 작성할 수 있으며, 여기서 명세별 속성 및 메서드를 정의할 수 있습니다:

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 요청 중 하나의 추상화입니다.

jobjob type을 가지며, register, update, unregister 중 하나입니다.

jobstorage key(storage key)를 가집니다.

jobscope url(URL)을 가집니다.

jobscript url(URL)을 가집니다.

jobworker type("classic" 또는 "module")을 가집니다.

jobupdate via cache mode("imports", "all", "none") 중 하나입니다.

jobclient(서비스 워커 클라이언트)를 가지며, 초기값은 null입니다.

jobreferrer(URL 또는 null)을 가집니다.

jobjob promise(promise)를 가지며, 초기값은 null입니다.

jobcontaining job queue(job queue 또는 null)을 가지며, 초기값은 null입니다.

job동등 job 리스트(job 리스트)이며, 초기값은 빈 리스트입니다.

jobforce bypass cache flag를 가지며, 초기값은 unset입니다.

job동등이려면 job type이 동일해야 하며, 다음 조건을 만족해야 합니다:

job queue는 동시 job 집합의 동기화를 위해 사용되는 thread-safe 입니다. job queuejobitem으로 포함하며, 초기값은 비어 있습니다.

scope to job queue map은 키가 scope url(직렬화됨)이고, 값이 job queue순서가 있는 맵입니다.

잘못된 import 스크립트 응답은 아래 조건 중 하나를 만족하는 response입니다:

작업 생성

입력

jobType, 작업 타입

storage key, 스토리지 키

scopeURL, URL

scriptURL, URL

promise, 프라미스

client, 서비스 워커 클라이언트

출력

job, 작업

  1. job을 새로운 작업으로 둔다.

  2. job작업 타입jobType으로 설정한다.

  3. job스토리지 키storage key로 설정한다.

  4. jobscope urlscopeURL로 설정한다.

  5. jobscript urlscriptURL로 설정한다.

  6. job작업 프라미스promise로 설정한다.

  7. job클라이언트client로 설정한다.

  8. client가 null이 아니면, jobreferrerclient생성 URL로 설정한다.

  9. job을 반환한다.

작업 스케줄

입력

job, 작업

출력

없음

  1. jobQueue를 null로 둔다.

  2. jobScopejobscope url직렬화된 값으로 둔다.

  3. scope to job queue map[jobScope]가 존재하지 않으면, scope to job queue map[jobScope]에 새 작업 큐를 설정한다.

  4. jobQueuescope to job queue map[jobScope]로 설정한다.

  5. jobQueue가 비어 있으면:

    1. jobcontaining job queuejobQueue로 설정하고, jobQueue에 job을 enqueue한다.

    2. 작업 실행jobQueue로 호출한다.

  6. 그 외의 경우:

    1. lastJobjobQueue의 마지막 요소로 둔다.

    2. job동등하고 lastJob작업 프라미스가 아직 settle되지 않았다면, joblastJob동등 작업 리스트에 추가한다.

    3. 그 외에는, jobcontaining job queuejobQueue로 설정하고, jobQueue에 job을 enqueue한다.

작업 실행

입력

jobQueue, 작업 큐

출력

없음

  1. 단언: jobQueue비어 있지 않음을 보장한다.

  2. 작업을 큐에 추가하여 다음 단계를 실행한다:

    1. jobjobQueue의 첫 번째 item으로 둔다.

    2. job작업 타입register라면, 등록job병렬로 실행한다.

    3. 그 외에 job작업 타입update라면, 업데이트job병렬로 실행한다.

      참고: register 작업과 update 작업의 경우, 사용자 에이전트는 작업 실행을 위한 작업 큐 추가를, 해당 작업을 시작한 문서에서 DOMContentLoaded 이벤트가 디스패치된 이후로 지연시킨다.

    4. 그 외에 job작업 타입unregister라면, 등록 해제job병렬로 실행한다.

작업 완료

입력

job, 작업

출력

없음

  1. jobQueuejobcontaining job queue로 둔다.

  2. 단언: jobQueue의 첫 번째 itemjob임을 보장한다.

  3. jobQueue에서 dequeue한다.

  4. jobQueue비어 있지 않으면, 작업 실행jobQueue로 호출한다.

작업 프라미스 해결

입력

job, 작업

value, 임의 값

출력

없음

  1. job클라이언트가 null이 아니면, 작업을 큐에 추가하여, job클라이언트책임 이벤트 루프에서 DOM 조작 태스크 소스를 사용하여 다음을 실행한다:

    1. convertedValue를 null로 둔다.

    2. job작업 타입register 또는 update라면, convertedValue서비스 워커 등록 객체 얻기 결과로 valuejob클라이언트를 인자로 설정한다.

    3. 그 외에는 convertedValuevalue로, job클라이언트Realm에서 설정한다.

    4. job작업 프라미스convertedValue로 해결한다.

  2. job동등 작업 리스트의 각 equivalentJob에 대해:

    1. equivalentJob클라이언트가 null이면, 다음 반복으로 넘어간다.

    2. 작업을 큐에 추가하여, equivalentJob클라이언트책임 이벤트 루프에서 DOM 조작 태스크 소스를 사용하여 다음을 실행한다:

      1. convertedValue를 null로 둔다.

      2. equivalentJob작업 타입register 또는 update라면, convertedValue서비스 워커 등록 객체 얻기 결과로 valueequivalentJob클라이언트를 인자로 설정한다.

      3. 그 외에는 convertedValuevalue로, equivalentJob클라이언트Realm에서 설정한다.

      4. equivalentJob작업 프라미스convertedValue로 해결한다.

작업 프라미스 거부

입력

job, 작업

errorData, 예외 생성에 필요한 정보

출력

없음

  1. job클라이언트가 null이 아니면, 작업을 큐에 추가하여, job클라이언트책임 이벤트 루프에서 DOM 조작 태스크 소스를 사용하여, job작업 프라미스새로운 예외 (errorData, job클라이언트Realm)로 reject 한다.

  2. job동등 작업 리스트의 각 equivalentJob에 대해:

    1. equivalentJob클라이언트가 null이면, 다음 반복으로 넘어간다.

    2. 작업을 큐에 추가하여, equivalentJob클라이언트책임 이벤트 루프에서 DOM 조작 태스크 소스를 사용하여, equivalentJob작업 프라미스새로운 예외 (errorData, equivalentJob클라이언트Realm)로 reject 한다.

등록 시작

입력

scopeURL, URL 또는 실패 또는 null

scriptURL, URL 또는 실패

promise, 프라미스

client, 서비스 워커 클라이언트

referrer, URL

workerType, 워커 타입

updateViaCache, update via cache mode

출력

없음

  1. scriptURL이 실패이면, promiseTypeError로 reject하고 이 단계를 중단한다.

  2. scriptURLfragment를 null로 설정한다.

    참고: 사용자 에이전트는 스크립트 url의 fragment를 저장하지 않는다. 즉, fragment는 서비스 워커 식별에 영향을 주지 않는다.

  3. scriptURLscheme이 "http", "https"가 아니면, promiseTypeError로 reject하고 이 단계를 중단한다.

  4. scriptURLpath에 포함된 어떤 문자열이 ASCII 대소문자 구분 없이 "%2f", "%5c"를 포함하면, promiseTypeError로 reject하고 이 단계를 중단한다.

  5. scopeURL이 null이면, scopeURL"./" 문자열과 scriptURL로 파싱한 결과로 설정한다.

    참고: 등록의 기본 scope url은 서비스 워커 스크립트 위치로 설정된다.

  6. scopeURL이 실패이면, promiseTypeError로 reject하고 이 단계를 중단한다.

  7. scopeURLfragment를 null로 설정한다.

    참고: 사용자 에이전트는 scope url의 fragment를 저장하지 않는다. 즉, fragment는 서비스 워커 등록 식별에 영향을 주지 않는다.

  8. scopeURLscheme이 "http", "https"가 아니면, promiseTypeError로 reject하고 이 단계를 중단한다.

  9. scopeURLpath에 포함된 어떤 문자열이 ASCII 대소문자 구분 없이 "%2f", "%5c"를 포함하면, promiseTypeError로 reject하고 이 단계를 중단한다.

  10. storage key클라이언트에서 스토리지 키 얻기 결과로 설정한다.

  11. job작업 생성register, storage key, scopeURL, scriptURL, promise, client로 실행한 결과로 둔다.

  12. job워커 타입workerType으로 설정한다.

  13. jobupdate via cache modeupdateViaCache로 설정한다.

  14. jobreferrerreferrer로 설정한다.

  15. 작업 스케줄job로 호출한다.

등록

입력

job, 작업

출력

없음

  1. 잠재적으로 신뢰할 수 있는 오리진 알고리즘을 jobscript url의 오리진에 대해 실행한 결과가 Not Trusted이면:

    1. 작업 프라미스 거부job과 "SecurityError" DOMException"로 호출한다.

    2. 작업 완료job로 호출하고 이 단계를 중단한다.

  2. jobscript url오리진jobreferrer오리진동일 오리진이 아니면:

    1. 작업 프라미스 거부job과 "SecurityError" DOMException"로 호출한다.

    2. 작업 완료job로 호출하고 이 단계를 중단한다.

  3. jobscope url오리진jobreferrer오리진동일 오리진이 아니면:

    1. 작업 프라미스 거부job과 "SecurityError" DOMException"로 호출한다.

    2. 작업 완료job로 호출하고 이 단계를 중단한다.

  4. registration등록 가져오기job스토리지 키jobscope url로 실행한 결과로 둔다.

  5. registration이 null이 아니면:

    1. newestWorker최신 워커 가져오기registration에 대해 실행한 결과로 둔다.

    2. newestWorker가 null이 아니고, jobscript url동등하고, job워커 타입newestWorkertype과 같고, jobupdate via cache mode 값이 registrationupdate via cache mode와 같으면:

      1. 작업 프라미스 해결jobregistration으로 호출한다.

      2. 작업 완료job로 호출하고 이 단계를 중단한다.

  6. 그 외에는:

    1. 등록 설정 알고리즘을 job스토리지 키, jobscope url, jobupdate via cache mode로 실행한다.

  7. 업데이트 알고리즘을 job로 실행한다.

업데이트

입력

job, 작업

출력

없음

  1. registration등록 가져오기job스토리지 키jobscope url로 실행한 결과로 둔다.

  2. registration이 null이면:

    1. 작업 프라미스 거부jobTypeError로 호출한다.

    2. 작업 완료job로 호출하고 이 단계를 중단한다.

  3. newestWorker최신 워커 가져오기 알고리즘을 registration에 대해 실행한 결과로 둔다.

  4. job작업 타입update이고, newestWorker가 null이 아니면서 newestWorkerscript url동등하지 않으면 jobscript url과:

    1. 작업 프라미스 거부jobTypeError로 호출한다.

    2. 작업 완료job로 호출하고 이 단계를 중단한다.

  5. hasUpdatedResources를 false로 둔다.

  6. updatedResourceMap순서가 있는 맵으로 두고, URL이고 응답이다.

  7. job워커 타입에 따라 다음 옵션으로 하위 단계를 실행한다:

    "classic"

    클래식 워커 스크립트 가져오기job직렬화된 script url, job클라이언트, "serviceworker", 그리고 이 서비스 워커의 환경 설정 객체로 실행한다.

    "module"

    모듈 워커 스크립트 그래프 가져오기job직렬화된 script url, job클라이언트, "serviceworker", "omit", 그리고 이 서비스 워커의 환경 설정 객체로 실행한다.

    이 알고리즘에서는 실제 환경 설정 객체 대신 생성될 환경 설정 객체를 사용한다. 이는 서비스 워커의 고유한 처리 모델 때문이다.

    HTML의 워커 스크립트 fetch 알고리즘은 job클라이언트를 인자로 받는다. job클라이언트Soft Update 알고리즘에서 전달받을 때 null이다.

    fetch hook 수행에서 request에 대해 다음 단계를 실행한다:

    1. request헤더 리스트에 `Service-Worker`/`script`를 추가한다.

      참고: Service-Worker 헤더 정의는 Appendix B에 있다.

    2. 다음 중 하나라도 참이면, request캐시 모드를 "no-cache"로 설정한다:

      참고: 캐시 모드가 "no-cache"가 아니더라도, 사용자 에이전트는 네트워크 계층의 Cache-Control 헤더의 max-age 값을 따르며 브라우저 캐시 우회 여부를 결정한다.

    3. requestservice-workers mode를 "none"으로 설정한다.

    4. isTopLevel 플래그가 설정되지 않았다면, fetching request 결과를 반환한다.

    5. requestredirect mode를 "error"로 설정한다.

    6. fetch request를 실행하고, processResponse의 일부로 response response에 대해 나머지 단계를 비동기로 실행한다.

    7. response헤더 리스트에서 MIME type 추출을 수행한다. 이 MIME 타입(파라미터 무시)이 자바스크립트 MIME 타입이 아니면:

      1. 작업 프라미스 거부job과 "SecurityError" DOMException"로 호출한다.

      2. 이 단계들을 비동기로 네트워크 에러로 완료한다.

    8. serviceWorkerAllowed헤더 리스트 값 추출으로 `Service-Worker-Allowed`와 response헤더 리스트로 얻는다.

      참고: Service-Worker-Allowed 헤더 정의는 Appendix B에 있다.

    9. policyContainerfetch 응답으로 정책 컨테이너 생성으로 response를 인자로 설정한다.

    10. serviceWorkerAllowed가 실패이면:

      1. 이 단계들을 비동기로 네트워크 에러로 완료한다.

    11. scopeURLregistrationscope url로 둔다.

    12. maxScopeString을 null로 둔다.

    13. serviceWorkerAllowed가 null이면:

      1. resolvedScope"./" 문자열과 jobscript url로 파싱한 결과로 둔다.

      2. maxScopeString을 "/" 다음에 resolvedScopepath 문자열(빈 문자열 포함)을 "/"로 구분하여 연결한 값으로 설정한다.

        참고: 마지막 resolvedScopepath 요소는 항상 빈 문자열이므로, maxScopeString은 마지막에 "/"가 있음.

    14. 그 외에는:

      1. maxScopeserviceWorkerAllowedjobscript url을 인자로 파싱한 결과로 둔다.

      2. maxScope오리진jobscript url오리진과 같으면:

        1. maxScopeString을 "/" 다음에 maxScopepath 문자열(빈 문자열 포함)을 "/"로 구분하여 연결한 값으로 설정한다.

    15. scopeString을 "/" 다음에 scopeURLpath 문자열(빈 문자열 포함)을 "/"로 구분하여 연결한 값으로 설정한다.

    16. maxScopeString이 null이거나 scopeStringmaxScopeString으로 시작하지 않으면:

      1. 작업 프라미스 거부job과 "SecurityError" DOMException"로 호출한다.

      2. 이 단계들을 비동기로 네트워크 에러로 완료한다.

    17. urlrequesturl로 둔다.

    18. updatedResourceMap[url] = response로 설정한다.

    19. responsecache state가 "local"이 아니면, registration마지막 업데이트 확인 시간을 현재 시간으로 설정한다.

    20. 다음 중 하나라도 참이면 hasUpdatedResources를 true로 설정한다:

      • newestWorker가 null인 경우

      • newestWorkerscript urlurl과 다르거나 newestWorkertypejobworker type과 다른 경우

      • newestWorkerscript resource map[url]의 bodyresponsebody와 바이트 단위로 동일하지 않은 경우

    21. hasUpdatedResources가 false이고 newestWorkerclassic scripts imported flag가 설정되어 있다면:

      참고: 아래는 import된 스크립트가 변경되었는지 확인하는 단계로, 메인 스크립트가 변경되지 않은 경우에만 검사한다.

      1. importUrlstoredResponsenewestWorkerscript resource map에서 반복한다:

        1. importUrlurl이면 다음 반복으로 간다.

        2. importRequest를 새 request로, urlimportUrl, clientjob클라이언트, destination은 "script", parser metadata는 "not parser-inserted", use-URL-credentials flag는 설정됨으로 생성한다.

        3. 다음 중 하나라도 참이면, importRequest캐시 모드를 "no-cache"로 설정한다:

        4. fetchedResponsefetching importRequest의 결과로 둔다.

        5. updatedResourceMap[importRequesturl] = fetchedResponse로 설정한다.

        6. fetchedResponsefetchedResponseunsafe response로 설정한다.

        7. fetchedResponsecache state가 "local"이 아니면, registration마지막 업데이트 확인 시간을 현재 시간으로 설정한다.

        8. fetchedResponse잘못된 import 스크립트 응답이면, 다음 반복으로 간다.

          참고: importScripts()의 잘못된 응답은 바이트 비교에서 무시된다.

        9. fetchedResponsebodystoredResponseunsafe responsebody와 바이트 단위로 동일하지 않으면, hasUpdatedResources를 true로 설정한다.

          참고: 이 단계에서는 모든 import 스크립트의 캐시 채우기를 위해 반복을 멈추지 않는다.

    22. 이 단계들을 비동기로 response로 완료한다.

    이 알고리즘이 비동기로 완료되면, 남은 단계들을 script를 비동기 완료 값으로 하여 계속한다.

  8. script가 null이거나 Is Async Modulescriptrecord, scriptbase URL, « »로 실행한 결과가 true이면:

    1. 작업 프라미스 거부jobTypeError로 호출한다.

      참고: 만약 이전 단계에서 작업 프라미스 거부가 "SecurityError" DOMException"로 호출되었다면 아무 동작하지 않는다.

    2. newestWorker가 null이면, 등록 맵[(registration스토리지 키, 직렬화된 scopeURL)]을 제거한다.

    3. 작업 완료job로 호출하고 이 단계를 중단한다.

  9. hasUpdatedResources가 false이면:

    1. registrationupdate via cache modejobupdate via cache mode로 설정한다.

    2. 작업 프라미스 해결jobregistration으로 호출한다.

    3. 작업 완료job로 호출하고 이 단계를 중단한다.

  10. worker를 새로운 서비스 워커로 둔다.

  11. workerscript urljobscript url로, workerscript resourcescript로, workertypejobworker type으로, workerscript resource mapupdatedResourceMap으로 설정한다.

  12. urlworker사용된 스크립트 집합에 추가한다.

  13. workerscript resourcepolicy containerpolicyContainer로 설정한다.

  14. forceBypassCachejobforce bypass cache flag가 설정되어 있으면 true, 아니면 false로 둔다.

  15. runResult서비스 워커 실행 알고리즘을 workerforceBypassCache로 실행한 결과로 둔다.

  16. runResult실패 또는 abrupt completion이면:

    1. 작업 프라미스 거부jobTypeError로 호출한다.

    2. newestWorker가 null이면, 등록 맵[(registration스토리지 키, 직렬화된 scopeURL)]을 제거한다.

    3. 작업 완료job로 호출한다.

  17. 그 외에는 설치 알고리즘을 job, worker, registration을 인자로 실행한다.

소프트 업데이트

사용자 에이전트는 업데이트를 확인하기 위해 원하는 만큼 자주 이 알고리즘을 호출할 수 있습니다.

입력

registration, 서비스 워커 등록

forceBypassCache, 선택적 불리언, 기본값은 false

참고: 구현자는 forceBypassCache를 디버깅(예: 개발자 도구에서 호출)이나 서비스 워커를 확장하는 다른 명세에서 필요에 따라 사용할 수 있습니다.

출력

없음

  1. newestWorker최신 워커 가져오기 알고리즘을 registration에 대해 실행한 결과로 둔다.

  2. newestWorker가 null이면 이 단계를 중단한다.

  3. job작업 생성update, registration스토리지 키, registrationscope url, newestWorkerscript url, null, null로 실행한 결과로 둔다.

  4. job워커 타입newestWorkertype으로 설정한다.

  5. forceBypassCache가 true이면 jobforce bypass cache flag를 설정한다.

  6. 작업 스케줄job로 호출한다.

설치

입력

job, 작업

worker, 서비스 워커

registration, 서비스 워커 등록

출력

없음

  1. installFailed를 false로 둔다.

  2. newestWorker최신 워커 가져오기 알고리즘을 registration에 대해 실행한 결과로 둔다.

  3. registrationupdate via cache modejobupdate via cache mode로 설정한다.

  4. 등록 상태 업데이트 알고리즘을 registration, "installing", worker로 실행한다.

  5. 워커 상태 업데이트 알고리즘을 registration설치 중인 워커, "installing"로 실행한다.

  6. 단언: job작업 프라미스는 null이 아니다.

  7. 작업 프라미스 해결jobregistration으로 호출한다.

  8. settingsObjects환경 설정 객체 중, 오리진registrationscope url오리진과 같은 모든 객체로 둔다.

  9. settingsObjects의 각 settingsObject에 대해, 작업을 큐에 추가하여 settingsObject책임 이벤트 루프에서 DOM 조작 태스크 소스로 다음 단계를 실행한다:

    1. registrationObjectssettingsObjectrealm에 있는 모든 ServiceWorkerRegistration 객체 중, service worker registrationregistration인 객체로 둔다.

    2. registrationObjects의 각 registrationObject에 대해, 이벤트 발행registrationObjectupdatefound 이름으로 실행한다.

  10. installingWorkerregistration설치 중인 워커로 둔다.

  11. 이벤트 생략 여부 알고리즘을 installingWorker와 "install"로 실행한 결과가 false이면:

    1. jobforce bypass cache flag가 설정되어 있으면 forceBypassCache를 true로, 아니면 false로 둔다.

    2. 서비스 워커 실행 알고리즘을 installingWorkerforceBypassCache로 실행한 결과가 실패이면:

      1. installFailed를 true로 설정한다.

    3. 그 외에는:

      1. installingWorker이벤트 루프에서 DOM 조작 태스크 소스task 작업을 큐에 추가해 다음 단계들을 실행한다:

        1. eInstallEvent이벤트 생성한 결과로 둔다.

        2. etype 속성을 install로 초기화한다.

        3. 이벤트 디스패치einstallingWorker글로벌 객체로 실행한다.

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

          1. eactive가 아니게 될 때까지 기다린다.

          2. etimed out flag가 설정되어 있으면 installFailed를 true로 설정한다.

          3. p모든 promise를 기다림으로 eextend lifetime promises로 실행한 결과로 둔다.

          4. p가 reject될 때 installFailed를 true로 설정한다.

        task가 버려지면 installFailed를 true로 설정한다.

      2. task가 실행되거나 버려질 때까지 기다린다.

      3. WaitForAsynchronousExtensions 단계가 완료될 때까지 기다린다.

  12. installFailed가 true이면:

    1. 워커 상태 업데이트 알고리즘을 registration설치 중인 워커, "redundant"로 실행한다.

    2. 등록 상태 업데이트 알고리즘을 registration, "installing", null로 실행한다.

    3. newestWorker가 null이면, 등록 맵[(registration스토리지 키, 직렬화된 registrationscope url)]을 제거한다.

    4. 작업 완료job로 호출하고 이 단계를 중단한다.

  13. mapregistration설치 중인 워커스크립트 리소스 맵으로 둔다.

  14. usedSetregistration설치 중인 워커사용된 스크립트 집합으로 둔다.

  15. urlmap에서 반복하여:

    1. usedSeturl포함되지 않으면 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()이 비동기로 호출되거나, 기존 extend lifetime promises가 settle될 때 다시 시도된다.

활성화

입력

registration, 서비스 워커 등록

출력

없음

  1. registration대기 중인 워커가 null이면 이 단계를 중단한다.

  2. registration활성 워커가 null이 아니면:

    1. 서비스 워커 종료registration활성 워커로 실행한다.

    2. 워커 상태 업데이트 알고리즘을 registration활성 워커, "redundant"로 실행한다.

  3. 등록 상태 업데이트 알고리즘을 registration, "active", registration대기 중인 워커로 실행한다.

  4. 등록 상태 업데이트 알고리즘을 registration, "waiting", null로 실행한다.

  5. 워커 상태 업데이트 알고리즘을 registration활성 워커, "activating"로 실행한다.

    참고: 활성 워커가 activating 상태가 되면 런타임 스크립트 오류나 강제 종료가 발생해도 활성 워커가 활성화되는 것을 막지 않는다.

    참고: 활성화 핸들러는 필수적이지 않은 작업(예: 정리 작업)을 하도록 설계하는 것이 좋다. 브라우저가 활성화 중에 종료되는 등 모든 핸들러가 반드시 끝까지 실행되는 것은 아니기 때문이다. 활성화 핸들러가 모두 성공적으로 완료되지 않아도 서비스 워커가 정상적으로 동작해야 한다.

  6. matchedClients리스트로 두고, 서비스 워커 클라이언트creation URLregistration스토리지 키registrationscope url에 매칭되는 클라이언트로 둔다.

  7. clientmatchedClients에서 반복하여, 작업을 큐에 추가하여 client책임 이벤트 루프에서 DOM 조작 태스크 소스로 다음 하위 단계들을 실행한다:

    1. readyPromiseclient글로벌 객체ServiceWorkerContainer 객체의 ready promise로 둔다.

    2. readyPromise가 null이면 다음 반복으로 넘어간다.

    3. readyPromise가 pending 상태이면, 서비스 워커 등록 객체 얻기registrationreadyPromiserelevant settings object로 실행한 결과로 readyPromise를 resolve한다.

  8. 등록을 사용 중인 서비스 워커 클라이언트 client마다:

    1. client활성 워커registration활성 워커로 설정한다.

    2. 컨트롤러 변경 알림 알고리즘을 client에 대해 실행한다.

  9. activeWorkerregistration활성 워커로 둔다.

  10. 이벤트 생략 여부 알고리즘을 activeWorker와 "activate"로 실행한 결과가 false이면:

    1. 서비스 워커 실행 알고리즘을 activeWorker로 실행한 결과가 실패가 아니면:

      1. activeWorker이벤트 루프DOM 조작 태스크 소스task 작업을 큐에 추가해 다음 단계들을 실행한다:

        1. eExtendableEvent이벤트 생성한 결과로 둔다.

        2. etype 속성을 activate로 초기화한다.

        3. 이벤트 디스패치eactiveWorker글로벌 객체로 실행한다.

        4. WaitForAsynchronousExtensions: eactive가 아니게 될 때까지 병렬로 기다린다.

      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 생성을 요구하지만, 구현체에서는 더 적은 작업으로도 충분할 수 있다. 구현체는 이 알고리즘에서 덜 하고, 서비스 워커 실행에서 더 해도 된다. 단, 결과가 관찰 가능한 수준에서 동일해야 한다(특히 모든 보안 검사 결과가 동일할 것).

  1. unsafeCreationTimeunsafe shared current time으로 둔다.

  2. serviceWorker실행 중이면, serviceWorker글로벌 객체를 반환한다.

  3. serviceWorker상태가 "redundant"이면 null을 반환한다.

  4. serviceWorker글로벌 객체가 null이 아니면 serviceWorker글로벌 객체를 반환한다.

  5. 단언: serviceWorkerstart status가 null임을 보장한다.

  6. setupFailed를 false로 둔다.

  7. globalObject를 null로 둔다.

  8. agent서비스 워커 agent 얻기로 설정하고, 그 context에서 다음 단계를 실행한다:

    1. realmExecutionContext새 realm 생성 알고리즘을 agent와 다음 커스텀으로 실행한 결과로 둔다:

      • 글로벌 객체로 새 ServiceWorkerGlobalScope 객체를 생성한다. workerGlobalScope를 생성된 객체로 둔다.

    2. settingsObject를 새 환경 설정 객체로 두고, 알고리즘을 다음과 같이 정의한다:

      realm execution context

      realmExecutionContext를 반환한다.

      module map

      workerGlobalScopemodule map을 반환한다.

      API base URL

      serviceWorkerscript url을 반환한다.

      오리진

      등록한 서비스 워커 클라이언트오리진을 반환한다.

      policy container

      workerGlobalScopepolicy container를 반환한다.

      time origin

      unsafeCreationTime을 coarsening한 결과로 workerGlobalScopecross-origin isolated capability를 인자로 한다.

    3. settingsObjectid를 새 고유 불투명 문자열로, creation URLserviceWorkerscript url로, top-level creation URL을 null로, top-level origin구현 정의 값으로, target browsing context를 null로, active service worker를 null로 설정한다.

    4. workerGlobalScopeurlserviceWorkerscript url로 설정한다.

    5. workerGlobalScopepolicy containerserviceWorkerscript resourcepolicy container로 설정한다.

    6. workerGlobalScopetypeserviceWorkertype으로 설정한다.

    7. WorkerLocation 객체를 생성하여 workerGlobalScope에 연결한다.

    8. 글로벌 객체 CSP 초기화 알고리즘을 workerGlobalScope에 실행한 결과가 "Blocked"이면, setupFailed를 true로 설정하고 이 단계를 중단한다.

    9. globalObjectworkerGlobalScope로 설정한다.

  9. globalObject가 null이 아니거나 setupFailed가 true가 될 때까지 기다린다.

  10. setupFailed가 true면 null을 반환한다.

  11. globalObject를 반환한다.

서비스 워커 실행

입력

serviceWorker, 서비스 워커

forceBypassCache, 선택적 불리언, 기본값은 false

출력

Completion 또는 실패

참고: 이 알고리즘은 서비스 워커가 실행 중이 되거나 시작에 실패할 때까지 블록됩니다.

  1. serviceWorker실행 중이면, serviceWorkerstart status를 반환한다.

  2. serviceWorkerstate가 "redundant"면 실패를 반환한다.

  3. 단언: serviceWorkerstart status는 null이다.

  4. scriptserviceWorker스크립트 리소스로 둔다.

  5. 단언: script는 null이 아니다.

  6. startFailed를 false로 둔다.

  7. workerGlobalScopeserviceWorker글로벌 객체로 둔다.

  8. workerGlobalScope가 null이면:

    1. workerGlobalScopeServiceWorkerGlobalScope 설정 알고리즘을 serviceWorker로 실행한 결과로 둔다.

    2. workerGlobalScope가 null이면 실패를 반환한다.

    3. serviceWorker글로벌 객체workerGlobalScope로 설정한다.

  9. workerGlobalScoperealm execution context에 대한 agent를 얻고, 그 context에서 다음 단계들을 실행한다:

    1. forceBypassCache가 true면 workerGlobalScopeimportScripts 캐시 우회 플래그를 설정한다.

    2. serviceWorker활성 워커이고, serviceWorker등록 객체task queue에 대기 중인 작업이 있으면, 해당 작업들을 serviceWorkerevent looptask queue에 원래 순서대로 해당 task source와 함께 큐에 추가한다.

    3. evaluationStatus를 null로 둔다.

    4. script클래식 스크립트이면:

      1. evaluationStatus클래식 스크립트 실행script로 실행한 결과로 둔다.

      2. evaluationStatus.[[Value]]가 비어 있으면, 스크립트가 평가되지 않은 것임. startFailed를 true로 설정하고 이 단계를 중단한다.

    5. 그 외에 script모듈 스크립트라면:

      1. evaluationPromise모듈 스크립트 실행script와 report errors=false로 실행한 결과로 둔다.

      2. 단언: evaluationPromise.[[PromiseState]]는 "pending"이 아니다.

      3. evaluationPromise.[[PromiseState]]가 "rejected"이면:

        1. evaluationStatusThrowCompletion(evaluationPromise.[[PromiseResult]])로 설정한다.

      4. 그 외에는:

        1. evaluationStatusNormalCompletion(undefined)로 설정한다.

    6. 스크립트가 서비스 워커 종료 알고리즘에 의해 중단되었다면, startFailed를 true로 설정하고 이 단계를 중단한다.

    7. serviceWorkerstart statusevaluationStatus로 설정한다.

    8. scripthas ever been evaluated flag가 설정되지 않았다면:

      1. settingsObject글로벌 객체에 연결된 이벤트 리스너의 event type마다:

        1. Append eventTypeworkerGlobalScope서비스 워커처리할 이벤트 타입 집합에 추가한다.

        참고: 글로벌 객체의 이벤트 리스너가 현재 추가되어 있지 않으면, 서비스 워커의 처리할 이벤트 타입 집합은 빈 집합으로 남는다.

      2. scripthas ever been evaluated flag를 설정한다.

      3. serviceWorker모든 fetch 리스너 비어 있음 플래그를 해제한다.

      4. 만약 모든 fetch 리스너 비어 있음 알고리즘을 workerGlobalScope로 실행한 결과가 true이면, serviceWorker모든 fetch 리스너 비어 있음 플래그를 설정할 수 있다.

    9. settingsObject가 지정한 책임 이벤트 루프를 파괴될 때까지 실행한다.

    10. Clear workerGlobalScope활성 타이머 맵을 초기화한다.

  10. serviceWorker실행 중이 되거나 startFailed가 true가 될 때까지 기다린다.

  11. startFailed가 true면 실패를 반환한다.

  12. serviceWorkerstart status를 반환한다.

모든 fetch 리스너 비어 있음

입력

workerGlobalScope, 글로벌 객체

출력

불리언 값

  1. workerGlobalScope처리할 이벤트 타입 집합fetch를 포함하지 않으면 true를 반환한다.

  2. eventHandlerworkerGlobalScopeevent handler map["onfetch"] 값으로 둔다.

  3. eventListenerCallbackslegacy-obtain service worker fetch event listener callbacksworkerGlobalScope에 대해 실행한 결과로 둔다.

  4. eventListenerCallbackeventListenerCallbacks에서 반복하여:

    1. callback을 null로 둔다.

    2. eventHandler가 null이 아니고 eventListenerCallbackeventHandlerlistenercallback과 같으면, callbackIDL을 ECMAScript 값으로 변환eventHandlervalue로 설정한다.

    3. 그 외에는 callbackIDL을 ECMAScript 값으로 변환eventListenerCallback으로 설정한다.

    4. IsCallable(callback)이 false이면 false를 반환한다.

      참고: Callback 객체가 handleEvent(event)를 사용하면 비어 있지 않은 것으로 간주한다. 이는 handleEvent(event) getter를 호출하는 것을 피하기 위함이다.

    5. callback함수 본문이 비어 있지 않으면(즉, 문장 또는 선언이 존재하면) false를 반환한다.

    참고: 이는 () => {}와 같은 빈 fetch 리스너를 탐지한다. 어떤 사이트들은 fetch 이벤트 리스너에 빈 본문을 추가하여 Chromium에서 PWA로 인식시키기도 한다.

  5. true를 반환한다.

참고: 사용자 에이전트는 불필요한 빈 "fetch" 리스너가 있을 때 경고를 표시하고, 성능에 악영향을 줄 수 있음을 안내할 수 있다.

서비스 워커 종료

입력

serviceWorker, 서비스 워커

출력

없음

  1. serviceWorker의 메인 루프와 병렬로 다음 단계를 실행한다:

    1. serviceWorkerGlobalScopeserviceWorker글로벌 객체로 둔다.

    2. serviceWorkerGlobalScopeclosing 플래그를 true로 설정한다.

    3. serviceWorker확장 이벤트 집합에서 모든 item제거한다.

    4. 작업task sourcehandle fetch task source 또는 handle functional event task source인 작업이 serviceWorkerGlobalScopeevent looptask queue에 대기 중이면, 해당 작업들을 serviceWorker등록 객체의 해당 task queue에 원래 순서대로 task source와 함께 큐에 추가하고, serviceWorkerGlobalScopeevent looptask queue에서 모든 작업(메시지 이벤트 등 포함)을 처리하지 않고 버린다.

      참고: 즉, fetch 이벤트와 다른 기능적 이벤트(push 등)는 등록 객체의 task queue로 백업되고, 메시지 등 나머지 작업은 버려진다.

    5. 현재 실행 중인 스크립트를 중단한다.

    6. serviceWorkerstart status를 null로 설정한다.

Fetch 처리

Fetch 처리 알고리즘은 fetch 처리를 서비스 워커 컨텍스트에 전달하는 진입점입니다.

입력

request, request

fetchController, fetch controller

useHighResPerformanceTimers, 불리언

출력

response

  1. registration을 null로 둔다.

  2. clientrequestclient로 둔다.

  3. reservedClientrequestreserved client로 둔다.

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

  5. workerRealm을 null로 둔다.

  6. timingInfo를 새로운 service worker timing info로 둔다.

  7. 단언: requestdestination은 "serviceworker"가 아님.

  8. requestdestination이 "embed" 또는 "object"이면:

    1. null을 반환한다.

  9. 그 외에 requestnon-subresource request라면:

    1. reservedClient가 null이 아니며 environment settings object라면:

      1. reservedClientsecure context가 아니면 null을 반환한다.

    2. 그 외에는:

      1. requesturl잠재적으로 신뢰할 수 있는 URL이 아니면 null을 반환한다.

    3. requestnavigation request이고, 이를 트리거한 navigation이 shift+reload 또는 동등한 동작으로 시작되었으면 null을 반환한다.

    4. 단언 reservedClient가 null이 아님을 보장한다.

    5. storage keyobtain a storage keyreservedClient로 실행한 결과로 둔다.

    6. registrationMatch Service Worker Registrationstorage key, requesturl로 실행한 결과로 둔다.

    7. registration이 null이거나 registration활성 워커가 null이면 null을 반환한다.

    8. requestdestination"report"가 아니면, reservedClientactive service workerregistration활성 워커로 설정한다.

    참고: 이 시점부터 서비스 워커 클라이언트use 상태가 되며 active service worker등록 객체를 사용한다.

  10. 그 외에 requestsubresource request라면:

    1. clientactive service worker가 null이 아니면, registrationclientactive service worker등록 객체로 설정한다.

    2. 그 외에는 null을 반환한다.

  11. activeWorkerregistration활성 워커로 둔다.

  12. 다음 중 하나라도 참이면 shouldSoftUpdate를 true로, 아니면 false로 둔다:

  13. activeWorker라우터 규칙 목록비어 있지 않으면:

    1. sourceGet Router Source 알고리즘을 registration활성 워커request로 실행한 결과로 둔다.

    2. source"network"인 경우:

      1. shouldSoftUpdate가 true이면 병렬로 소프트 업데이트 알고리즘을 registration으로 실행한다.

      2. null을 반환한다.

    3. 그 외에 source"cache" 또는 source["cacheName"]가 존재하면:

      1. shouldSoftUpdate가 true이면 병렬로 소프트 업데이트 알고리즘을 registration으로 실행한다.

      2. cacheNamecacheregistration스토리지 키name to cache map에서 반복한다.

        1. source["cacheName"]가 존재하고 source["cacheName"]가 cacheName이 아니면 다음 반복으로 간다.

        2. requestResponsesQuery Cacherequest, 새 CacheQueryOptions, cache로 실행한 결과로 둔다.

        3. requestResponses가 빈 리스트이면 null을 반환한다.

        4. 그 외에는:

          1. requestResponserequestResponses의 첫 번째 요소로 둔다.

          2. responserequestResponse의 response로 둔다.

          3. globalObjectactiveWorker글로벌 객체로 둔다.

          4. globalObject가 null이면:

            1. globalObjectServiceWorkerGlobalScope 설정activeWorker로 실행한 결과로 둔다.

          5. globalObject가 null이면 null을 반환한다.

          참고: 이는 CORS 체크를 위해 ServiceWorkerGlobalScope를 생성하는 단계이지만, 실제 구현체에서 반드시 이 객체를 생성하라는 뜻은 아니다.

          1. responsetype이 "opaque"이고, cross-origin resource policy checkglobalObject오리진, globalObject, "", responseinternal response로 실행한 결과가 blocked이면 null을 반환한다.

          2. response를 반환한다.

      3. null을 반환한다.

    4. 그 외에 source"race-network-and-fetch-handler"이고, requestmethod가 `GET`이면:

      1. shouldSoftUpdate가 true이면 병렬로 소프트 업데이트 알고리즘을 registration으로 실행한다.

      2. queue를 빈 queue로 둔다.

      3. raceFetchController를 null로 둔다.

      4. raceResponserace response로, value는 "pending"으로 둔다.

      5. 다음 하위 단계들을 병렬로 실행하되, abort when fetchControllerstate가 "terminated" 또는 "aborted"이면 중단한다:

        1. raceFetchControllerfetchrequest로 실행한 결과로 둔다. processResponse는 다음 단계로 처리한다:

          1. raceNetworkRequestResponsestatusok status이면:

            1. raceResponsevalueraceNetworkRequestResponse로 설정한다.

            2. Enqueue raceNetworkRequestResponsequeue에 추가한다.

          2. 그 외에는 raceResponsevaluenetwork error로 설정한다.

      6. If aborted이고 raceFetchController가 null이 아니면:

        1. Abort raceFetchController.

        2. raceResponserace response로, value는 null로 설정한다.

      7. preloadResponse를 undefined로 resolve한다.

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

        1. fetchHandlerResponseFetch 이벤트 생성 및 디스패치request, registration, useHighResPerformanceTimers, timingInfo, workerRealm, reservedClient, preloadResponse, raceResponse로 실행한 결과로 둔다.

        2. fetchHandlerResponse가 null이 아니고 network error가 아니며 raceFetchController가 null이 아니면, Abort raceFetchController.

        3. Enqueue fetchHandlerResponsequeue에 추가한다.

      9. queue가 빈 상태가 아닐 때까지 기다린다.

      10. dequeue queue의 결과를 반환한다.

    5. 단언: source는 "fetch-event"임.

  14. requestnavigation request이고, registrationnavigation preload enabled flag가 설정되어 있고, requestmethod가 `GET`이며, registration활성 워커처리할 이벤트 타입 집합fetch를 포함하고, registration활성 워커모든 fetch 리스너 비어 있음 플래그가 설정되지 않았다면:

    참고: 위 조건이 모두 참이나 registration활성 워커처리할 이벤트 타입 집합fetch를 포함하지 않으면, 사용자 에이전트는 개발자 콘솔에 경고를 표시할 수 있음.

    1. preloadRequestcloningrequest로 실행한 결과로 둔다.

    2. preloadRequestHeaderspreloadRequest헤더 리스트로 둔다.

    3. preloadResponseObjectResponse 객체로, Headers 객체와 연결된 상태로 생성하되 guard는 "immutable"로 한다.

    4. Append를 통해 preloadRequestHeaders헤더를 추가하되 name은 `Service-Worker-Navigation-Preload`, valueregistrationnavigation preload header value로 한다.

    5. preloadRequestservice-workers mode를 "none"으로 설정한다.

    6. preloadFetchController를 null로 둔다.

    7. 다음 하위 단계들을 병렬로 실행하되, abort when fetchControllerstate가 "terminated" 또는 "aborted"이면 중단한다:

      1. preloadFetchControllerfetching preloadRequest의 결과로 둔다.

        processResponsenavigationPreloadResponse로 실행할 때 하위 단계:

        1. navigationPreloadResponsetype이 "error"이면, preloadResponseTypeError로 reject하고 하위 단계를 종료한다.

        2. preloadResponseObjectnavigationPreloadResponse와 연결한다.

        3. preloadResponsepreloadResponseObject로 resolve한다.

    8. If aborted이면:

      1. deserializedErrordeserialize a serialized abort reason를 null, workerRealm으로 실행한 결과로 둔다.

      2. Abort preloadFetchControllerdeserializedError로 실행한다.

  15. 그 외에는 preloadResponse를 undefined로 resolve한다.

  16. Fetch 이벤트 생성 및 디스패치request, registration, useHighResPerformanceTimers, timingInfo, workerRealm, reservedClient, preloadResponse, null로 실행한 결과를 반환한다.

Fetch 이벤트 생성 및 디스패치

입력

request, request

registration, 서비스 워커 등록

useHighResPerformanceTimers, 불리언

timingInfo, service worker timing info

workerRealm, 글로벌 객체의 relevant realm

reservedClient, reserved client

preloadResponse, promise

raceResponse, race response 또는 null

출력

response

  1. response를 null로 둔다.

  2. eventCanceled를 false로 둔다.

  3. clientrequestclient로 둔다.

  4. activeWorkerregistration활성 워커로 둔다.

  5. eventHandled를 null로 둔다.

  6. handleFetchFailed를 false로 둔다.

  7. respondWithEntered를 false로 둔다.

  8. 다음 중 하나라도 참이면 shouldSoftUpdate를 true로, 아니면 false로 둔다:

  9. 이벤트 생략 여부 알고리즘을 "fetch", activeWorker로 실행한 결과가 true이면:

    1. shouldSoftUpdate가 true이면 병렬로 소프트 업데이트 알고리즘을 registration으로 실행한다.

    2. null을 반환한다.

  10. activeWorker모든 fetch 리스너 비어 있음 플래그가 설정되어 있으면:

    1. 병렬로:

      1. activeWorker상태가 "activating"이면, activeWorker상태가 "activated"가 될 때까지 기다린다.

      2. 서비스 워커 실행 알고리즘을 activeWorker로 실행한다.

      3. shouldSoftUpdate가 true이면 소프트 업데이트 알고리즘을 registration으로 실행한다.

    2. null을 반환한다.

  11. useHighResPerformanceTimers가 true이면, useHighResPerformanceTimersactiveWorker글로벌 객체cross-origin isolated capability로 설정한다.

  12. timingInfostart timecoarsened shared current timeuseHighResPerformanceTimers로 실행한 결과로 설정한다.

  13. activeWorker상태가 "activating"이면, activeWorker상태가 "activated"가 될 때까지 기다린다.

  14. 서비스 워커 실행 알고리즘을 activeWorker로 실행한 결과가 실패이면 handleFetchFailed를 true로 설정한다.

  15. 그 외에는:

    1. workerRealmactiveWorker글로벌 객체의 relevant realm로 설정한다.

    2. eventHandled새 promiseworkerRealm에 생성한다.

    3. raceResponse가 null이 아니면, 설정 activeWorker글로벌 객체race response map[request]를 raceResponse로 설정한다.

    4. 작업을 큐에 추가하여 task에서 다음 하위 단계를 실행한다:

      1. e이벤트 생성FetchEvent로 실행한 결과로 둔다.

      2. abortController AbortController 객체로 workerRealm에 생성한다.

      3. requestObjectRequest 객체 생성request, 새 Headers 객체의 guard는 "immutable", abortControllersignal, workerRealm로 실행한 결과로 둔다.

      4. etype 속성을 fetch로 초기화한다.

      5. ecancelable 속성을 true로 초기화한다.

      6. erequest 속성을 requestObject로 초기화한다.

      7. epreloadResponse 속성을 preloadResponse로 초기화한다.

      8. eclientId 속성을 clientid로 초기화한다.

      9. requestnon-subresource request이고, requestdestination"report"가 아니면, eresultingClientId 속성을 reservedClientid로, 아니면 빈 문자열로 초기화한다.

      10. requestnavigation request이면, ereplacesClientId 속성을 requestreplaces client id로, 아니면 빈 문자열로 초기화한다.

      11. ehandled 속성을 eventHandled로 초기화한다.

      12. timingInfofetch event dispatch timecoarsened shared current timeuseHighResPerformanceTimers로 실행한 결과로 설정한다.

      13. 이벤트 디스패치e, activeWorker글로벌 객체로 실행한다.

      14. 서비스 워커 확장 이벤트 집합 업데이트activeWorker, e로 실행한다.

      15. erespond-with entered flag가 설정되어 있으면 respondWithEntered를 true로 설정한다.

      16. ewait to respond flag가 설정되어 있으면:

        1. ewait to respond flag가 해제될 때까지 기다린다.

        2. erespond-with error flag가 설정되어 있으면 handleFetchFailed를 true로 설정한다.

        3. 그 외에는 responseepotential response로 설정한다.

      17. response가 null이고 requestbody가 null이 아니고, requestbodysource가 null이면:

        1. requestbodyunusable이면 handleFetchFailed를 true로 설정한다.

        2. 그 외에는 cancelrequestbody, undefined로 실행한다.

      18. response가 null이 아니면 responseservice worker timing infotimingInfo로 설정한다.

      19. ecanceled flag가 설정되어 있으면 eventCanceled를 true로 설정한다.

      20. fetchControllerstate가 "terminated" 또는 "aborted"이면:

        1. deserializedErrordeserialize a serialized abort reasonfetchControllerserialized abort reason, workerRealm으로 실행한 결과로 둔다.

        2. 작업을 큐에 추가하여 signal abortabortController, deserializedError로 실행한다.

      task가 버려지면 handleFetchFailed를 true로 설정한다.

      task는 반드시 activeWorkerevent loopfetch 처리 태스크 소스를 사용해야 한다.

  16. task가 실행되거나 handleFetchFailed가 true가 될 때까지 기다린다.

  17. shouldSoftUpdate가 true이면 병렬로 소프트 업데이트 알고리즘을 registration으로 실행한다.

  18. activeWorker글로벌 객체race response map[request]이 존재하면, 제거 activeWorker글로벌 객체race response map[request]을 제거한다.

  19. respondWithEntered가 false이면:

    1. eventCanceled가 true이면:

      1. eventHandled가 null이 아니면, reject eventHandled을 "NetworkError" DOMException"과 함께 workerRealm에서 reject한다.

      2. network error를 반환한다.

    2. eventHandled가 null이 아니면, resolve eventHandled을 실행한다.

    3. raceResponsevalue가 null이 아니면:

      1. raceResponsevalue가 "pending"이 아닐 때까지 기다린다.

      2. raceResponsevalueresponse이면, raceResponsevalue를 반환한다.

    4. null을 반환한다.

  20. handleFetchFailed가 true이면:

    1. eventHandled가 null이 아니면, reject eventHandled을 "NetworkError" DOMException"과 함께 workerRealm에서 reject한다.

    2. network error를 반환한다.

  21. eventHandled가 null이 아니면, resolve eventHandled을 실행한다.

  22. response를 반환한다.

URL 패턴 파싱

입력

rawPattern, URLPatternCompatible

serviceWorker, 서비스 워커

출력

URL 패턴

  1. baseURLserviceWorker스크립트 URL로 둔다.

  2. rawPatternbaseURL을 인자로 하여 Web IDL 값으로부터 URL 패턴 생성 알고리즘을 실행한 결과를 반환한다.

라우터 조건 검증

입력

condition, RouterCondition

serviceWorker, 서비스 워커

출력

불리언 값

  1. hasCondition을 false로 둔다.

  2. condition["urlPattern"] 존재하면:

    1. rawPatterncondition["urlPattern"]로 둔다.

    2. patternURL 패턴 파싱 알고리즘을 rawPattern, serviceWorker로 실행한 결과로 둔다. 만약 예외가 발생하면 false를 반환한다.

    3. pattern정규식 그룹을 포함하면 false를 반환한다.

      참고: 사용자 정의 정규식을 실행하는 것은 보안상 문제이므로 금지된다.

    4. hasCondition을 true로 설정한다.

  3. condition["requestMethod"] 존재하면:

    1. methodcondition["requestMethod"]로 둔다.

    2. methodmethod가 아니면 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. orConditionscondition["_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. orConditionscondition["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. rawPatterncondition["urlPattern"]로 둔다.

      2. patternURL 패턴 파싱 알고리즘을 rawPattern, serviceWorker로 실행한 결과로 둔다.

      3. match 알고리즘을 pattern, requestURL로 실행한 결과가 null이면 false를 반환한다.

    2. condition["requestMethod"] 존재하면:

      1. methodcondition["requestMethod"]로 둔다.

      2. method 정규화method로 실행한다.

      3. requestmethodmethod와 다르면 false를 반환한다.

    3. condition["requestMode"] 존재하면:

      1. modecondition["requestMode"]로 둔다.

      2. requestmodemode와 다르면 false를 반환한다.

    4. condition["requestDestination"] 존재하면:

      1. destinationcondition["requestDestination"]로 둔다.

      2. requestdestinationdestination과 다르면 false를 반환한다.

    5. condition["runningStatus"] 존재하면:

      1. runningStatuscondition["runningStatus"]로 둔다.

      2. runningStatus"running"이고, serviceWorker실행 중이 아니면 false를 반환한다.

      3. runningStatus"not-running"이고, serviceWorker실행 중이면 false를 반환한다.

    6. true를 반환한다.

라우터 등록 제한 검사

입력

routerRules, 라우터 규칙 리스트

출력

불리언 값

참고: 라우터 조건은 _ornot을 사용하여 복잡하게 중첩될 수 있습니다. 과도한 처리를 방지하기 위해, 이 알고리즘은 두 가지 제한을 둡니다. 첫째, 중첩된 모든 조건을 합한 총 조건 수는 1024를 초과할 수 없습니다. 둘째, 중첩 깊이는 10단계로 제한하여 계산량이 지수적으로 증가하는 것을 막습니다.

  1. result라우터 조건 카운트 결과로 둔다.

  2. resultcondition count를 1024로 설정한다.

  3. resultquota exceeded를 false로 설정한다.

  4. rulerouterRules에서 반복하여:

    1. result내부 라우터 조건 카운트 알고리즘을 rule["condition"], result, 10으로 실행한 결과로 둔다.

    2. resultquota exceeded가 true면 false를 반환한다.

  5. true를 반환한다.

내부 라우터 조건 카운트

입력

condition, RouterCondition

result, 라우터 조건 카운트 결과

depth, 숫자

출력

result, 라우터 조건 카운트 결과

  1. resultcondition count를 1 감소시킨다.

  2. resultcondition count가 0이거나, depth가 0이면:

    1. resultquota exceeded를 true로 설정한다.

    2. result를 반환한다.

  3. condition["_or"]가 존재하면:

    1. depth를 1 감소시킨다.

    2. condition["_or"]의 각 orCondition에 대해:

      1. result내부 라우터 조건 카운트 알고리즘을 orCondition, result, depth로 실행한 결과로 둔다.

      2. resultquota exceeded가 true면 result를 반환한다.

  4. 그 외에 condition["not"]가 존재하면:

    1. depth를 1 감소시킨다.

    2. result내부 라우터 조건 카운트 알고리즘을 condition["not"], result, depth로 실행한 결과로 둔다.

    3. resultquota exceeded가 true면 result를 반환한다.

  5. result를 반환한다.

라우터 소스 확인

입력

serviceWorker, 서비스 워커

request, request

출력

RouterSource 또는 null

  1. ruleserviceWorker라우터 규칙 리스트에서 반복하여:

    1. 라우터 조건 매칭 알고리즘을 rule["condition"], serviceWorker, request로 실행한 결과가 true면, rule["source"]를 반환한다.

  2. null을 반환한다.

이벤트 생략 여부

입력

eventName, 문자열

serviceWorker, 서비스 워커

출력

불리언 값

참고: 불필요한 지연을 피하기 위해, 이 표준은 서비스 워커의 글로벌에서 이벤트 리스너가 최초 스크립트 실행 시 결정적으로 추가되지 않은 경우 이벤트 디스패치를 생략할 수 있도록 허용합니다.

  1. serviceWorker처리할 이벤트 타입 집합eventName포함되지 않으면, 사용자 에이전트는 true를 반환할 수 있습니다.

  2. false를 반환한다.

기능성 이벤트 발행

입력

eventName, 문자열

eventConstructor, ExtendableEvent를 확장한 이벤트 생성자

registration, 서비스 워커 등록

initialization, eventeventConstructor로 생성할 때 사용할 속성 초기화 (옵션)

postDispatchSteps, 활성 워커의 이벤트 루프에서 eventConstructor의 인스턴스(dispatchedEvent)가 디스패치된 후 실행할 단계 (옵션)

출력

없음

  1. 단언: registration활성 워커는 null이 아니다.

  2. activeWorkerregistration활성 워커로 둔다.

  3. 이벤트 생략 여부 알고리즘을 eventName, activeWorker로 실행한 결과가 true면:

    1. registrationstale이면 병렬로 소프트 업데이트 알고리즘을 registration으로 실행한다.

    2. 반환한다.

  4. activeWorker상태가 "activating"이면, activeWorker상태가 "activated"가 될 때까지 기다린다.

  5. 서비스 워커 실행 알고리즘을 activeWorker로 실행한 결과가 실패이면:

    1. registrationstale이면 병렬로 소프트 업데이트 알고리즘을 registration으로 실행한다.

    2. 반환한다.

  6. 작업을 큐에 추가하여 task에서 다음 하위 단계를 실행한다:

    1. event이벤트 생성eventConstructoractiveWorker글로벌 객체의 relevant realm으로 실행한 결과로 둔다.

    2. initialization이 null이 아니면, eventinitialization으로 초기화한다.

    3. 이벤트 디스패치event, activeWorker글로벌 객체로 실행한다.

    4. 서비스 워커 확장 이벤트 집합 업데이트activeWorker, event로 실행한다.

    5. postDispatchSteps가 null이 아니면, postDispatchStepseventdispatchedEvent로 전달하여 실행한다.

    task는 반드시 activeWorker이벤트 루프기능성 이벤트 태스크 소스를 사용해야 한다.

  7. task가 실행되거나 버려질 때까지 기다린다.

  8. registrationstale이면 병렬로 소프트 업데이트 알고리즘을 registration으로 실행한다.

"amazingthing" 이벤트(AmazingThingEvent 타입)를 특정 serviceWorkerRegistration에 발행하고, 이벤트 객체의 속성을 초기화하려면 다음과 같이 기술합니다:
  1. 기능성 이벤트 발행 "amazingthing"를 AmazingThingEventserviceWorkerRegistration에 다음 속성으로 발행:

    propertyName

    value

    anotherPropertyName

    anotherValue

    그리고 dispatchedEvent로 다음 단계를 수행합니다:

    1. 서비스 워커의 이벤트 루프에서 dispatchedEvent로 필요한 작업을 수행합니다.

초기화 단계와 디스패치 후 단계는 옵션임을 참고하세요. 필요 없다면 다음과 같이 기술합니다:

  1. 기능성 이벤트 발행 "whatever"를 ExtendableEventserviceWorkerRegistration에 발행.

서비스 워커 클라이언트 언로드 처리

사용자 에이전트는 서비스 워커 클라이언트문서 언로드 정리 단계 또는 종료에 의해 언로드될 때 반드시 다음 단계를 실행해야 합니다.

입력

client, 서비스 워커 클라이언트

출력

없음

  1. 다음 단계를 원자적으로 실행한다.

  2. registrationclient사용 중인 서비스 워커 등록으로 둔다.

  3. registration이 null이면 이 단계를 중단한다.

  4. 다른 서비스 워커 클라이언트registration사용 중이면 이 단계를 중단한다.

  5. registration등록 해제됨이면, 등록 정리 시도registration으로 호출한다.

  6. 활성화 시도registration으로 호출한다.

사용자 에이전트 종료 처리

입력

없음

출력

없음

  1. registration등록 맵에서 반복한다:

    1. registration설치 중인 워커가 null이 아니면:

      1. registration대기 중인 워커활성 워커가 모두 null이면, 등록 정리registration으로 호출하고 다음 반복으로 넘어간다.

      2. 그 외에는 registration설치 중인 워커를 null로 설정한다.

    2. registration대기 중인 워커가 null이 아니면 병렬로:

      1. 활성화registration으로 호출한다.

서비스 워커 확장 이벤트 집합 업데이트

입력

worker, 서비스 워커

event, 이벤트

출력

없음

  1. 단언: eventdispatch flag는 해제되어 있다.

  2. worker확장 이벤트 집합의 각 item에 대해:

    1. itemactive가 아니면, 제거 worker확장 이벤트 집합에서 item을 제거한다.

  3. eventactive이면, append eventworker확장 이벤트 집합에 추가한다.

등록 해제

입력

job, 작업

출력

없음

  1. joboriginjobclientorigin이 다르면:

    1. 작업 프라미스 거부job, "SecurityError" DOMException"로 호출한다.

    2. 작업 완료job로 호출하고 이 단계를 중단한다.

  2. registration등록 가져오기job스토리지 키, jobscope url로 실행한 결과로 둔다.

  3. registration이 null이면:

    1. 작업 프라미스 해결job, false로 호출한다.

    2. 작업 완료job로 호출하고 이 단계를 중단한다.

  4. 등록 맵[(registration스토리지 키, jobscope url)]을 제거한다.

  5. 작업 프라미스 해결job, true로 호출한다.

  6. 등록 정리 시도registration으로 호출한다.

    참고: 등록 정리 시도가 여기에서 등록 정리를 트리거하지 않으면, 등록 정리는 등록을 사용 중인 마지막 클라이언트가 언로드되거나, 등록의 서비스 워커에 대한 extend lifetime promises가 settle될 때 다시 시도된다.

  7. 작업 완료job로 호출한다.

등록 설정

입력

storage key, 스토리지 키

scope, URL

updateViaCache, update via cache mode

출력

registration, 서비스 워커 등록

  1. 다음 단계를 원자적으로 실행한다.

  2. scopeString직렬화된 scope로 하되, fragment 제외 플래그를 설정한다.

  3. registration을 새 서비스 워커 등록으로 두고, 스토리지 키storage key로, scope urlscope로, update via cache modeupdateViaCache로 설정한다.

  4. 등록 맵[(storage key, scopeString)]에 registration을 설정한다.

  5. registration을 반환한다.

등록 정리

입력

registration, 서비스 워커 등록

출력

없음

  1. 다음 단계를 원자적으로 실행한다.

  2. registration설치 중인 워커가 null이 아니면:

    1. 서비스 워커 종료registration설치 중인 워커로 실행한다.

    2. 워커 상태 업데이트 알고리즘을 registration설치 중인 워커, "redundant"로 실행한다.

    3. 등록 상태 업데이트 알고리즘을 registration, "installing", null로 실행한다.

  3. registration대기 중인 워커가 null이 아니면:

    1. 서비스 워커 종료registration대기 중인 워커로 실행한다.

    2. 워커 상태 업데이트 알고리즘을 registration대기 중인 워커, "redundant"로 실행한다.

    3. 등록 상태 업데이트 알고리즘을 registration, "waiting", null로 실행한다.

  4. registration활성 워커가 null이 아니면:

    1. 서비스 워커 종료registration활성 워커로 실행한다.

    2. 워커 상태 업데이트 알고리즘을 registration활성 워커, "redundant"로 실행한다.

    3. 등록 상태 업데이트 알고리즘을 registration, "active", null로 실행한다.

등록 정리 시도

입력

registration, 서비스 워커 등록

출력

없음

  1. 다음 조건을 모두 만족하고 서비스 워커 클라이언트registration사용하지 않으면 등록 정리registration으로 호출한다:

등록 상태 업데이트

입력

registration, 서비스 워커 등록

target, 문자열 ("installing", "waiting", "active" 중 하나)

source, 서비스 워커 또는 null

출력

없음

  1. registrationObjectsregistration과 연결된 모든 ServiceWorkerRegistration 객체 배열로 둔다.

  2. target이 "installing"이면:

    1. registration설치 중인 워커source로 설정한다.

    2. registrationObjects의 각 registrationObject에 대해:

      1. 작업을 큐에 추가하여 registrationObjectinstalling 속성을 registration설치 중인 워커가 null이면 null로, 아니면 서비스 워커 객체 얻기 알고리즘을 registration설치 중인 워커registrationObjectrelevant settings object로 실행한 결과로 설정한다.

  3. 그 외에 target이 "waiting"이면:

    1. registration대기 중인 워커source로 설정한다.

    2. registrationObjects의 각 registrationObject에 대해:

      1. 작업을 큐에 추가하여 registrationObjectwaiting 속성을 registration대기 중인 워커가 null이면 null로, 아니면 서비스 워커 객체 얻기 알고리즘을 registration대기 중인 워커registrationObjectrelevant settings object로 실행한 결과로 설정한다.

  4. 그 외에 target이 "active"이면:

    1. registration활성 워커source로 설정한다.

    2. registrationObjects의 각 registrationObject에 대해:

      1. 작업을 큐에 추가하여 registrationObjectactive 속성을 registration활성 워커가 null이면 null로, 아니면 서비스 워커 객체 얻기 알고리즘을 registration활성 워커registrationObjectrelevant settings object로 실행한 결과로 설정한다.

    작업registrationObjectrelevant settings object책임 이벤트 루프DOM 조작 태스크 소스를 사용해야 한다.

워커 상태 업데이트

입력

worker, 서비스 워커

state, 서비스 워커 상태

출력

없음

  1. 단언: state는 "parsed"가 아니다.

    참고: "parsed"는 초기 상태이다. 서비스 워커는 이 상태로 업데이트되지 않는다.

  2. worker상태state로 설정한다.

  3. settingsObjects환경 설정 객체originworker스크립트 URLorigin인 것들의 집합으로 둔다.

  4. settingsObjects의 각 settingsObject에 대해, 작업을 큐에 추가하여 settingsObject책임 이벤트 루프DOM 조작 태스크 소스로 다음 단계 실행:

    1. objectMapsettingsObject서비스 워커 객체 맵으로 둔다.

    2. objectMap[worker]가 존재하지 않으면 이 단계를 중단한다.

    3. workerObjobjectMap[worker]로 둔다.

    4. workerObjstate 속성을 state로 설정한다.

    5. "statechange" 이벤트 발행workerObj에 실행한다.

컨트롤러 변경 알림

입력

client, 서비스 워커 클라이언트

출력

없음

  1. 단언: client는 null이 아니다.

  2. client환경 설정 객체라면, 작업을 큐에 추가하여 controllerchange 이벤트를 client연결된 ServiceWorkerContainer 객체에 발행한다.

작업client책임 이벤트 루프DOM 조작 태스크 소스를 사용해야 한다.

서비스 워커 등록 매칭

입력

storage key, 스토리지 키

clientURL, URL

출력

서비스 워커 등록

  1. 다음 단계를 원자적으로 실행한다.

  2. clientURLString직렬화된 clientURL로 둔다.

  3. matchingScopeString을 빈 문자열로 둔다.

  4. scopeStringSet을 빈 리스트로 둔다.

  5. (entry storage key, entry scope)를 등록 맵에서 반복하여:

    1. storage key동일하다면, append entry scopescopeStringSet에 추가한다.

  6. matchingScopeStringscopeStringSetclientURLString으로 시작하는 가장 긴 값으로 설정한다(존재하면).

    참고: 이 단계의 URL 문자열 매칭은 접두사 기반으로 경로 구조와 무관하다. 예를 들어, 클라이언트 URL 문자열이 "https://example.com/prefix-of/resource.html"이면, "https://example.com/prefix" 범위에 등록된 경우 매칭된다. 동일 오리진 보안에 안전함을 보장하기 위해 HTTP(S) URL은 항상 오리진 부분 끝에 슬래시가 붙어 직렬화된다.

  7. matchingScope를 null로 둔다.

  8. matchingScopeString이 빈 문자열이 아니면:

    1. matchingScope파싱 matchingScopeString의 결과로 둔다.

    2. 단언: matchingScopeoriginclientURLorigin동일 오리진이다.

  9. 등록 가져오기storage key, matchingScope로 실행한 결과를 반환한다.

등록 가져오기

입력

storage key, 스토리지 키

scope, URL

출력

서비스 워커 등록

  1. 다음 단계를 원자적으로 실행한다.

  2. scopeString을 빈 문자열로 둔다.

  3. scope가 null이 아니면, scopeString직렬화된 scope로 하되 fragment 제외 플래그를 설정한다.

  4. (entry storage key, entry scope) → registration등록 맵에서 반복하여:

    1. storage key동일하고 scopeStringentry scope와 일치하면 registration을 반환한다.

  5. null을 반환한다.

최신 워커 가져오기

입력

registration, 서비스 워커 등록

출력

newestWorker, 서비스 워커

  1. 다음 단계를 원자적으로 실행한다.

  2. newestWorker를 null로 둔다.

  3. registration설치 중인 워커가 null이 아니면, newestWorkerregistration설치 중인 워커로 설정한다.

  4. 그 외에 registration대기 중인 워커가 null이 아니면, newestWorkerregistration대기 중인 워커로 설정한다.

  5. 그 외에 registration활성 워커가 null이 아니면, newestWorkerregistration활성 워커로 설정한다.

  6. newestWorker를 반환한다.

서비스 워커에 보류 중인 이벤트 없음

입력

worker, 서비스 워커

출력

True 또는 false, 불리언

  1. worker확장 이벤트 집합의 각 event에 대해:

    1. eventactive이면, false를 반환한다.

  2. true를 반환한다.

클라이언트 생성

입력

client, 서비스 워커 클라이언트

출력

clientObject, Client 객체

  1. clientObject를 새 Client 객체로 둔다.

  2. clientObject서비스 워커 클라이언트client로 설정한다.

  3. clientObject를 반환한다.

윈도우 클라이언트 생성

입력

client, 서비스 워커 클라이언트

frameType, 문자열

visibilityState, 문자열

focusState, 불리언

ancestorOriginsList, 리스트

출력

windowClient, WindowClient 객체

  1. windowClient를 새 WindowClient 객체로 둔다.

  2. windowClient서비스 워커 클라이언트client로 설정한다.

  3. windowClient프레임 타입frameType으로 설정한다.

  4. windowClient가시성 상태visibilityState로 설정한다.

  5. windowClient포커스 상태focusState로 설정한다.

  6. windowClientancestor origins arrayfrozen arrayancestorOriginsList로부터 생성하여 설정한다.

  7. windowClient를 반환한다.

프레임 타입 가져오기

입력

navigable, navigable

출력

frameType, 문자열

  1. navigableparent가 null이 아니면 "nested"를 반환한다.

  2. navigableactive browsing context보조 브라우징 컨텍스트라면 "auxiliary"를 반환한다.

  3. "top-level"을 반환한다.

Get Client Promise 해석

입력

client, 서비스 워커 클라이언트

promise, 프라미스

출력

없음

  1. client환경 설정 객체라면:

    1. client보안 컨텍스트가 아니면, 작업을 큐에 추가하여 promise를 "SecurityError" DOMException으로 거부하고, promiserelevant settings object책임 이벤트 루프DOM 조작 태스크 소스를 사용하고, 이 단계를 중단한다.

  2. 그 외의 경우:

    1. clientcreation URL잠재적으로 신뢰할 수 있는 URL이 아니면, 작업을 큐에 추가하여 promise를 "SecurityError" DOMException으로 거부하고, promiserelevant settings object책임 이벤트 루프DOM 조작 태스크 소스를 사용하고, 이 단계를 중단한다.

  3. client환경 설정 객체이고 window client가 아니면:

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

    2. 작업을 큐에 추가하여 promiseclientObject로 resolve하고, promiserelevant settings object책임 이벤트 루프DOM 조작 태스크 소스를 사용하고, 이 단계를 중단한다.

  4. 그 외의 경우:

    1. browsingContext를 null로 둔다.

    2. client환경 설정 객체이면, browsingContextclient글로벌 객체browsing context로 둔다.

    3. 그 외에는 browsingContextclienttarget browsing context로 둔다.

    4. navigablenavigable로 두고, active browsing contextbrowsingContext로 둔다.

    5. 작업을 큐에 추가하여 browsingContextevent loop에서 user interaction task source를 사용하여 다음 단계 실행:

      1. frameType프레임 타입 가져오기 알고리즘을 navigable로 실행한 결과로 둔다.

      2. visibilityStatebrowsingContextactive documentvisibilityState 값으로 둔다.

      3. focusStatehas focus steps 알고리즘을 browsingContextactive document로 실행한 결과로 둔다.

      4. ancestorOriginsList를 빈 리스트로 둔다.

      5. clientwindow client라면, ancestorOriginsListbrowsingContextactive documentrelevant global objectLocation 객체의 ancestor origins list의 리스트로 둔다.

      6. 작업을 큐에 추가하여 promiserelevant settings object책임 이벤트 루프DOM 조작 태스크 소스로 다음 단계 실행:

        1. clientdiscarded flag가 설정되어 있으면 promise를 undefined로 resolve하고 이 단계를 중단한다.

        2. windowClient윈도우 클라이언트 생성 알고리즘을 client, frameType, visibilityState, focusState, ancestorOriginsList로 실행한 결과로 둔다.

        3. promisewindowClient로 resolve한다.

캐시 질의

입력

requestQuery, request

options, CacheQueryOptions 객체, 옵션

targetStorage, request response list, 옵션

출력

resultList, request response list

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

  2. storage를 null로 둔다.

  3. 옵션 인자 targetStorage가 생략되었다면, storagerelevant request response list로 설정한다.

  4. 그 외에는 storagetargetStorage로 설정한다.

  5. requestResponsestorage에서 반복하여:

    1. cachedRequestrequestResponse의 request로 둔다.

    2. cachedResponserequestResponse의 response로 둔다.

    3. 요청이 캐시 항목과 일치 알고리즘을 requestQuery, cachedRequest, cachedResponse, options로 실행한 결과가 true이면:

      1. requestCopycachedRequest의 복사본으로 둔다.

      2. responseCopycachedResponse의 복사본으로 둔다.

      3. requestCopy/responseCopyresultList에 추가한다.

  6. resultList를 반환한다.

요청이 캐시 항목과 일치

입력

requestQuery, request

request, request

response, response 또는 null, 선택적, 기본값은 null

options, CacheQueryOptions 객체, 선택적

출력

불리언 값

  1. options["ignoreMethod"]가 false이고 requestmethod가 `GET`이 아니면 false를 반환한다.

  2. queryURLrequestQueryurl로 둔다.

  3. cachedURLrequesturl로 둔다.

  4. options["ignoreSearch"]가 true이면:

    1. cachedURLquery를 빈 문자열로 설정한다.

    2. queryURLquery를 빈 문자열로 설정한다.

  5. queryURLcachedURLfragment 제외 플래그를 설정한 상태로 동일하지 않으면 false를 반환한다.

  6. response가 null이거나, options["ignoreVary"]가 true이거나, responseheader list에 `Vary`가 포함되지 않으면 true를 반환한다.

  7. fieldValues리스트로 두고, field-valuesVary 헤더의 에 해당하는 요소들로 구성한다.

  8. fieldValues의 각 fieldValue에 대해:

    1. fieldValue가 "*"와 일치하거나, combined valuefieldValue, requestheader list로 실행한 결과가 combined valuefieldValue, requestQueryheader list로 실행한 결과와 일치하지 않으면 false를 반환한다.

  9. true를 반환한다.

캐시 일괄 작업

입력

operations, 리스트캐시 일괄 작업 객체

출력

resultList, request response list

  1. cacherelevant request response list로 둔다.

  2. backupCachecache의 복사본으로 새 request response list로 둔다.

  3. addedItems를 빈 리스트로 둔다.

  4. 다음 하위 단계를 원자적으로 시도한다:

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

    2. operationoperations에서 반복하여:

      1. operationtype이 "delete"도 "put"도 아니면 TypeError를 throw한다.

      2. operationtype이 "delete"이고 operationresponse가 null이 아니면 TypeError를 throw한다.

      3. 캐시 질의 알고리즘을 operationrequest, operationoptions, addedItems로 실행한 결과가 비어 있지 않으면 InvalidStateError DOMException을 throw한다.

      4. requestResponses를 빈 리스트로 둔다.

      5. operationtype이 "delete"이면:

        1. requestResponses캐시 질의 알고리즘을 operationrequest, operationoptions로 실행한 결과로 설정한다.

        2. requestResponserequestResponses에서 반복하여:

          1. Remove 값이 requestResponse와 일치하는 itemcache에서 제거한다.

      6. 그 외에 operationtype이 "put"이면:

        1. operationresponse가 null이면 TypeError를 throw한다.

        2. roperationrequestrequest로 둔다.

        3. rurlscheme이 "http" 또는 "https"가 아니면 TypeError를 throw한다.

        4. rmethod가 `GET`이 아니면 TypeError를 throw한다.

        5. operationoptions가 null이 아니면 TypeError를 throw한다.

        6. requestResponses캐시 질의 알고리즘을 operationrequest로 실행한 결과로 둔다.

        7. requestResponserequestResponses에서 반복하여:

          1. Remove 값이 requestResponse와 일치하는 itemcache에서 제거한다.

        8. Append operationrequest/operationresponsecache에 추가한다.

        9. 이전 두 단계에서 캐시 쓰기 작업이 할당된 quota 한도 초과로 실패하면, QuotaExceededError DOMException을 throw한다.

        10. Append operationrequest/operationresponseaddedItems에 추가한다.

      7. Append operationrequest/operationresponseresultList에 추가한다.

    3. resultList를 반환한다.

  5. 그리고 만약 예외가 throw되었다면:

    1. Remove 모든 itemrelevant request response list에서 제거한다.

    2. requestResponsebackupCache에서 반복하여:

      1. Append requestResponserelevant request response list에 추가한다.

    3. Throw 해당 예외를 throw한다.

    참고: 예외가 throw되면, 구현체는 일괄 작업 중 캐시 저장소에 가한 변경 사항을 모두 undo(롤백)해야 한다.

비동기 모듈 여부 확인

입력

record, 모듈 레코드

moduleMap, 모듈 맵

base, URL

seen, URL 집합

출력

불리언 값

  1. record순환 모듈 레코드가 아니면:

    1. false를 반환한다.

  2. record.[[Async]]가 true면:

    1. true를 반환한다.

  3. 문자열 requestedrecord.[[RequestedModules]]에서 반복한다:

    1. url모듈 지정자 해석base, requested로 실행한 결과로 둔다.

    2. 단언: url은 실패가 아니며, 모듈 지정자 해석이 이전에 동일 인자로 성공한 적이 있다.

    3. seenurl없으면:

      1. Append urlseen에 추가한다.

      2. moduleMap[url]에 레코드가 없으면:

        1. false를 반환한다.

      3. 비동기 모듈 여부 확인moduleMap[url]의 레코드, moduleMap, base, seen으로 실행한 결과가 true면:

        1. true를 반환한다.

  4. false를 반환한다.

경쟁 응답 조회

입력

request, request

출력

response 또는 null

  1. registration을 null로 둔다.

  2. requestnon-subresource request이면:

    1. requestreserved client가 null이면 null을 반환한다.

    2. storage key스토리지 키 획득requestreserved client로 실행한 결과로 둔다.

    3. registration서비스 워커 등록 매칭storage key, requesturl로 실행한 결과로 둔다.

  3. 그 외에 requestsubresource request이면:

    1. clientrequestclient로 둔다.

    2. clientactive service worker가 null이면 null을 반환한다.

    3. registrationclientactive service worker소속 서비스 워커 등록으로 둔다.

  4. 그 외의 경우 null을 반환한다.

  5. activeWorkerregistrationactive worker로 둔다.

  6. mapactiveWorker글로벌 객체race response map으로 둔다.

  7. map[request]이 존재하면:

    1. entrymap[request]로 둔다.

    2. Remove map[request]을 제거한다.

    3. entryvalue가 "pending"이 아닐 때까지 기다린다.

    4. entryvalueresponse이면, entryvalue를 반환한다.

  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. 콘텐츠 보안 정책 레벨 3. 2025년 2월 6일. 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. 파일 API. 2024년 12월 4일. WD. URL: https://www.w3.org/TR/FileAPI/
[HR-TIME-3]
Yoav Weiss. 고해상도 시간. 2024년 11월 7일. WD. URL: https://www.w3.org/TR/hr-time-3/
[HTML]
Anne van Kesteren; 외. 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 Sniffing 표준. 현행 표준. URL: https://mimesniff.spec.whatwg.org/
[NAVIGATION-TIMING-2]
Yoav Weiss; Noam Rosenthal. 네비게이션 타이밍 레벨 2. 2025년 2월 13일. WD. URL: https://www.w3.org/TR/navigation-timing-2/
[PAGE-LIFECYCLE]
페이지 라이프사이클. 커뮤니티 그룹 초안 보고서. URL: https://wicg.github.io/page-lifecycle/
[PAGE-VISIBILITY]
Jatinder Mann; Arvind Jain. 페이지 가시성 (제2판). 2013년 10월 29일. REC. URL: https://www.w3.org/TR/page-visibility/
[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/rfc/rfc5234
[RFC7230]
R. Fielding, Ed.; J. Reschke, Ed.. Hypertext Transfer Protocol (HTTP/1.1): 메시지 문법과 라우팅. 2014년 6월. 제안 표준. URL: https://httpwg.org/specs/rfc7230.html
[RFC7231]
R. Fielding, Ed.; J. Reschke, Ed.. Hypertext Transfer Protocol (HTTP/1.1): 의미와 콘텐츠. 2014년 6월. 제안 표준. URL: https://httpwg.org/specs/rfc7231.html
[SCREEN-CAPTURE]
Jan-Ivar Bruaroey; Elad Alon. 스크린 캡처. 2025년 2월 13일. 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. 스토리지 표준. 현행 표준. URL: https://storage.spec.whatwg.org/
[STREAMS]
Adam Rice; 외. Streams 표준. 현행 표준. URL: https://streams.spec.whatwg.org/
[TRUSTED-TYPES]
Krzysztof Kotowicz. Trusted Types. 2025년 1월 10일. 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 패턴 표준. 현행 표준. 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<undefined> 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의 클래식 워커 스크립트 가져오기 알고리즘과 모듈 워커 스크립트 그래프 가져오기 알고리즘은 jobclient를 인자로 받습니다. Soft Update 알고리즘에서 전달될 때 jobclient는 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?