출시된 내용, 영향이 측정된 방식, 절충된 사항에 관한 이야기
배경
Google에서 거의 모든 주제를 검색하면 의미 있고 관련성 높은 결과가 즉시 표시됩니다. 이 검색 결과 페이지는 특정 시나리오에서 서비스 워커라는 강력한 웹 기술에 의해 제공된다는 사실을 모르셨을 수도 있습니다.
성능에 부정적인 영향을 미치지 않으면서 Google 검색에 서비스 워커 지원을 출시하려면 여러 팀에서 수십 명의 엔지니어가 협력해야 했습니다. 출시된 내용, 성능 측정 방법, 절충된 사항에 관한 이야기입니다.
서비스 워커를 살펴볼 주요 이유
웹 앱에 서비스 워커를 추가하는 것은 사이트의 아키텍처를 변경하는 것과 마찬가지로 명확한 목표를 염두에 두고 진행해야 합니다. Google 검색팀에서 서비스 워커를 추가하는 것이 좋겠다고 생각한 몇 가지 주요 이유는 다음과 같습니다.
제한된 검색 결과 캐싱
Google 검색팀은 사용자가 짧은 시간 내에 동일한 검색어를 두 번 이상 검색하는 경우가 많다는 사실을 발견했습니다. 동일한 결과를 얻기 위해 새 백엔드 요청을 트리거하는 대신 검색팀은 캐싱을 활용하고 이러한 반복 요청을 로컬에서 처리하고자 했습니다.
최신성의 중요성은 간과할 수 없으며, 사용자가 동일한 용어를 반복적으로 검색하는 경우도 있습니다. 이는 주제가 계속 진화하고 있어 최신 결과를 기대하기 때문입니다. 서비스 워커를 사용하면 검색팀에서 세분화된 로직을 구현하여 로컬에 캐시된 검색 결과의 전체 기간을 제어하고 사용자에게 가장 적합하다고 생각하는 속도와 최신성의 정확한 균형을 유지할 수 있습니다.
의미 있는 오프라인 환경
또한 Google 검색팀은 의미 있는 오프라인 환경을 제공하고자 했습니다. 사용자가 특정 주제에 관해 알아보려면 인터넷 연결 상태를 신경 쓰지 않고 Google 검색 페이지로 바로 이동하여 검색을 시작하고 싶어 합니다.
서비스 워커가 없으면 오프라인 상태에서 Google 검색 페이지를 방문하면 브라우저의 표준 네트워크 오류 페이지로 연결되며, 사용자는 연결이 복원된 후에 다시 방문하여 다시 시도해야 합니다. 서비스 워커를 사용하면 맞춤 오프라인 HTML 응답을 게재하고 사용자가 즉시 검색어를 입력할 수 있도록 허용할 수 있습니다.
인터넷에 연결될 때까지 결과를 사용할 수 없지만 서비스 워커를 사용하면 기기가 백그라운드 동기화 API를 사용하여 다시 온라인 상태가 되면 검색을 지연하고 Google 서버로 전송할 수 있습니다.
더 스마트한 JavaScript 캐싱 및 제공
또 다른 동기는 검색 결과 페이지의 다양한 유형의 기능을 지원하는 모듈식 JavaScript 코드의 캐싱 및 로드를 최적화하는 것이었습니다. 서비스 워커가 관여하지 않는 경우에 적합한 JavaScript 번들링의 이점이 많기 때문에 검색팀은 번들링을 완전히 중단하고 싶지 않았습니다.
검색팀은 서비스 워커의 기능을 사용하여 런타임에 세분화된 JavaScript 청크의 버전을 지정하고 캐시하면 캐시 변경 횟수를 줄이고 향후 재사용되는 JavaScript를 효율적으로 캐시할 수 있을 것으로 생각했습니다. 서비스 워커 내의 로직은 여러 JavaScript 모듈이 포함된 번들의 발신 HTTP 요청을 분석하고 로컬에 캐시된 여러 모듈을 조합하여 이를 처리할 수 있습니다. 즉, 가능하면 효과적으로 '번들 해제'합니다. 이렇게 하면 사용자 대역폭이 절약되고 전반적인 응답성이 개선됩니다.
서비스 워커에서 제공하는 캐시된 JavaScript를 사용하면 성능도 향상됩니다. Chrome에서는 해당 JavaScript의 파싱된 바이트 코드 표현이 저장되고 재사용되므로 페이지에서 JavaScript를 실행하기 위해 런타임에 실행해야 하는 작업이 줄어듭니다.
도전과제 및 솔루션
다음은 팀의 명시된 목표를 달성하기 위해 극복해야 했던 몇 가지 장애물입니다. 이러한 문제 중 일부는 Google 검색에만 해당하지만 대부분은 서비스 워커 배포를 고려 중인 다양한 사이트에 적용할 수 있습니다.
문제: 서비스 워커 오버헤드
Google 검색에서 서비스 워커를 실행하는 데 가장 큰 도전과제이자 진정한 장애물은 서비스 워커가 사용자 인식 지연 시간을 늘릴 수 있는 작업을 하지 않도록 하는 것이었습니다. Google 검색은 성능을 매우 중요하게 생각하며, 과거에는 특정 사용자 집단의 지연 시간이 10밀리초라도 늘어나는 경우 새 기능 출시를 차단했습니다.
팀이 초기 실험 중에 성능 데이터를 수집하기 시작했을 때 문제가 발생할 것이라는 것이 분명해졌습니다. 검색 결과 페이지의 탐색 요청에 대한 응답으로 반환되는 HTML은 동적이며 검색의 웹 서버에서 실행해야 하는 로직에 따라 크게 다릅니다. 현재 서비스 워커가 이 로직을 복제하고 캐시된 HTML을 즉시 반환할 방법은 없습니다. 가장 좋은 방법은 네트워크 요청이 필요한 백엔드 웹 서버에 탐색 요청을 전달하는 것입니다.
서비스 워커가 없으면 이 네트워크 요청은 사용자 탐색 시 즉시 발생합니다. 서비스 워커가 등록되면 항상 시작되어야 하며, 가져오기 핸들러가 네트워크로 이동하는 것 외의 작업을 할 가능성이 없는 경우에도 fetch
이벤트 핸들러를 실행할 기회가 주어져야 합니다. 서비스 작업자 코드를 시작하고 실행하는 데 걸리는 시간은 모든 탐색 위에 추가되는 순수 오버헤드입니다.
이렇게 하면 서비스 워커 구현이 지연 시간에 너무 불리해져 다른 이점을 얻을 수 없습니다. 또한 실제 기기에서 서비스 워커 부팅 시간을 측정한 결과, 시작 시간이 광범위하게 분포되어 있는 것으로 나타났으며, 일부 저가형 휴대기기의 경우 서비스 워커를 시작하는 데 걸리는 시간이 결과 페이지의 HTML에 대한 네트워크 요청을 실행하는 데 걸리는 시간과 거의 비슷했습니다.
해결 방법: 탐색 미리 로드 사용
Google 검색팀이 서비스 워커 출시를 진행할 수 있게 해준 가장 중요한 기능은 탐색 미리 로드입니다. 탐색 미리 로드는 탐색 요청을 충족하기 위해 네트워크의 응답을 사용해야 하는 모든 서비스 워커의 핵심적인 성능 개선사항입니다. 서비스 워커가 시작되는 동시에 즉시 탐색 요청을 시작하라는 힌트를 브라우저에 제공합니다.
서비스 워커가 시작되는 데 걸리는 시간이 네트워크에서 응답을 다시 가져오는 데 걸리는 시간보다 짧으면 서비스 워커로 인해 지연 시간 오버헤드가 발생하지 않습니다.
또한 검색팀은 서비스 워커 부팅 시간이 탐색 요청을 초과할 수 있는 저가형 휴대기기에서 서비스 워커를 사용하지 않아야 했습니다. '하위 엔드' 기기를 구성하는 요소에 대한 확실한 규칙이 없으므로 기기에 설치된 총 RAM을 확인하는 휴리스틱을 고안했습니다. 메모리가 2GB 미만인 기기는 서비스 워커 시작 시간이 허용되지 않는 저가형 기기 카테고리에 속했습니다.
향후 사용을 위해 캐시할 전체 리소스 세트가 수 메가바이트까지 실행될 수 있으므로 사용 가능한 저장용량도 고려해야 합니다. navigator.storage
인터페이스를 사용하면 Google 검색 페이지에서 데이터를 캐시하려고 할 때 스토리지 한도 실패로 인해 실패할 위험이 있는지 미리 파악할 수 있습니다.
이를 통해 검색팀은 서비스 워커를 사용할지 여부를 결정하는 데 사용할 수 있는 여러 기준을 마련했습니다. 사용자가 탐색 미리 로드를 지원하고 RAM이 2GB 이상이며 충분한 여유 저장공간이 있는 브라우저를 사용하여 Google 검색 페이지에 방문하면 서비스 워커가 등록됩니다. 이 기준을 충족하지 않는 브라우저나 기기는 서비스 워커가 실행되지 않지만 항상 동일한 Google 검색 환경이 표시됩니다.
이 선택적 등록의 한 가지 부수적인 이점은 더 작고 효율적인 서비스 워커를 제공할 수 있다는 것입니다. 서비스 워커 코드를 실행하기 위해 상당히 최신 브라우저를 타겟팅하면 이전 브라우저의 트랜스파일링 및 폴리필 오버헤드가 제거됩니다. 이렇게 하여 서비스 워커 구현의 총 크기에서 약 8KB의 비압축 JavaScript 코드가 제거되었습니다.
문제: 서비스 워커 범위
검색팀에서 충분한 지연 실험을 실행하고 내비게이션 미리 로드를 사용하면 서비스 워커를 사용하는 데 지연 시간이 중립적인 실행 경로를 제공할 수 있다고 확신하게 되자 몇 가지 실용적인 문제가 전면에 떠오르기 시작했습니다. 이러한 문제 중 하나는 서비스 워커의 범위 지정 규칙과 관련이 있습니다. 서비스 워커의 범위에 따라 서비스 워커가 제어할 수 있는 페이지가 결정됩니다.
범위 지정은 URL 경로 접두어를 기반으로 작동합니다. 단일 웹 앱을 호스팅하는 도메인의 경우 이는 문제가 되지 않습니다. 일반적으로 최대 범위가 /
인 서비스 워커를 사용하기 때문에 이 서비스 워커는 도메인 아래의 모든 페이지를 제어할 수 있습니다.
하지만 Google 검색의 URL 구조는 조금 더 복잡합니다.
서비스 워커에 최대 범위인 /
가 할당되면 www.google.com
(또는 지역별 상응하는 도메인)에서 호스팅되는 모든 페이지를 제어할 수 있게 되며, 이 도메인 아래에는 Google 검색과 관련이 없는 URL이 있습니다. 더 합리적이고 제한적인 범위는 /search
입니다. 이 범위에서는 적어도 검색 결과와 완전히 관련 없는 URL은 제외됩니다.
안타깝게도 이 /search
URL 경로조차도 Google 검색 결과의 다양한 버전 간에 공유되며, URL 쿼리 매개변수에 따라 표시되는 검색 결과의 특정 유형이 결정됩니다. 이러한 버전 중 일부는 기존 웹 검색 결과 페이지와 완전히 다른 코드베이스를 사용합니다. 예를 들어 이미지 검색과 쇼핑 검색은 모두 서로 다른 쿼리 매개변수를 사용하여 /search
URL 경로 아래에 게재되지만, 두 인터페이스 모두 아직 자체 서비스 워커 환경을 제공할 준비가 되지 않았습니다.
해결 방법: 전달 및 라우팅 프레임워크 만들기
URL 경로 접두사보다 강력한 방법으로 서비스 워커 범위를 결정할 수 있는 몇 가지 제안이 있지만 Google 검색팀은 제어하는 페이지의 하위 집합에 아무것도 하지 않는 서비스 워커를 배포하는 데 어려움을 겪었습니다.
이 문제를 해결하기 위해 Google 검색팀은 클라이언트 페이지의 쿼리 매개변수와 같은 기준을 확인하고 이를 사용하여 실행할 특정 코드 경로를 결정하도록 구성할 수 있는 맞춤 전달 및 라우팅 프레임워크를 빌드했습니다. 이 시스템은 규칙을 하드코딩하는 대신 유연하게 작동하도록 빌드되었으며, 이미지 검색 및 쇼핑 검색과 같이 URL 공간을 공유하는 팀이 나중에 자체 서비스 워커 로직을 구현하기로 결정할 경우 이를 적용할 수 있습니다.
문제: 맞춤 검색결과 및 측정항목
사용자는 Google 계정을 사용하여 Google 검색에 로그인할 수 있으며, 검색 결과 환경은 특정 계정 데이터를 기반으로 맞춤설정될 수 있습니다. 로그인한 사용자는 오래되고 널리 지원되는 표준인 특정 브라우저 쿠키로 식별됩니다.
하지만 브라우저 쿠키를 사용하는 한 가지 단점은 서비스 워커 내부에서 노출되지 않으며 값을 자동으로 검사하고 사용자가 로그아웃하거나 계정을 전환하여 변경되지 않았는지 확인할 방법이 없다는 것입니다. 서비스 워커에 쿠키 액세스를 제공하기 위한 작업이 진행 중이지만 이 글을 작성하는 시점에서는 이 접근 방식이 실험용이며 광범위하게 지원되지 않습니다.
현재 로그인한 사용자에 대한 서비스 워커의 뷰와 Google 검색 웹 인터페이스에 로그인한 실제 사용자가 일치하지 않으면 검색 결과가 잘못 맞춤설정되거나 측정항목 및 로깅에 기여도가 잘못 부여될 수 있습니다. 이러한 실패 시나리오는 Google 검색팀에 심각한 문제입니다.
해결 방법: postMessage를 사용하여 쿠키 전송
실험용 API가 출시되어 서비스 워커 내에서 브라우저의 쿠키에 직접 액세스할 수 있을 때까지 기다리지 않고 Google 검색팀은 임시 해결 방법을 사용했습니다. 서비스 워커가 제어하는 페이지가 로드될 때마다 페이지가 관련 쿠키를 읽고 postMessage()
를 사용하여 서비스 워커로 전송합니다.
그러면 서비스 워커가 예상하는 값과 현재 쿠키 값을 확인하고 일치하지 않는 경우 스토리지에서 사용자별 데이터를 삭제하는 조치를 취하고 잘못된 맞춤설정 없이 검색 결과 페이지를 새로고침합니다.
서비스 워커가 기준점으로 재설정하기 위해 취하는 구체적인 단계는 Google 검색의 요구사항에 따라 다르지만, 브라우저 쿠키를 기반으로 개인 맞춤 데이터를 처리하는 다른 개발자에게도 동일한 일반적인 접근 방식이 유용할 수 있습니다.
문제: 실험 및 역동성
앞서 언급한 바와 같이 Google 검색팀은 프로덕션에서 실험을 실행하고 새로운 코드와 기능을 기본적으로 사용 설정하기 전에 실제 환경에서 그 효과를 테스트하는 데 많은 의존하고 있습니다. 캐시된 데이터에 크게 의존하는 정적 서비스 워커의 경우 이는 약간 어려운 일일 수 있습니다. 실험에 참여하거나 참여하지 않도록 사용자를 선택하려면 백엔드 서버와 통신해야 하는 경우가 많기 때문입니다.
해결 방법: 동적으로 생성된 서비스 워커 스크립트
팀에서 선택한 해결 방법은 사전에 생성되는 단일 정적 서비스 워커 스크립트 대신 웹 서버에서 각 개별 사용자에 맞게 맞춤설정된 동적으로 생성된 서비스 워커 스크립트를 사용하는 것이었습니다. 서비스 워커의 동작이나 일반적인 네트워크 요청에 영향을 줄 수 있는 실험에 관한 정보는 이 맞춤설정된 서비스 워커 스크립트에 직접 포함됩니다. 사용자의 활성 환경 세트를 변경하는 작업은 브라우저 쿠키와 같은 기존 기법을 조합하고 등록된 서비스 워커 URL에 업데이트된 코드를 제공하는 방식으로 이루어집니다.
동적으로 생성된 서비스 워커 스크립트를 사용하면 서비스 워커 구현에 피해야 할 심각한 버그가 발생할 경우 더 쉽게 탈출구를 제공할 수 있습니다. 동적 서버 워커 응답은 no-op 구현일 수 있으며, 이 경우 현재 사용자의 일부 또는 전체에 대해 서비스 워커가 사실상 사용 중지됩니다.
문제: 업데이트 조정
실제 서비스 워커 배포에서 직면하는 가장 어려운 문제 중 하나는 캐시를 위해 네트워크를 사용하지 않는 것과 동시에 프로덕션에 배포된 직후 기존 사용자가 중요한 업데이트와 변경사항을 받을 수 있도록 하는 것 사이에서 적절한 절충점을 찾는 것입니다. 적절한 균형은 다음과 같은 여러 요인에 따라 달라집니다.
- 웹 앱이 사용자가 새 페이지로 이동하지 않고도 무기한 열어 두는 장기 실행 단일 페이지 앱인지 여부입니다.
- 백엔드 웹 서버 업데이트의 배포 주기입니다.
- 평균적인 사용자가 약간 오래된 버전의 웹 앱을 사용할 수 있는지 또는 최신성이 가장 중요한지 여부입니다.
서비스 워커를 실험하는 동안 Google 검색팀은 측정항목과 사용자 환경이 재방문 사용자가 실제로 보게 되는 환경과 더 밀접하게 일치하도록 여러 번의 예약된 백엔드 업데이트에서 실험을 계속 실행했습니다.
해결 방법: 최신성 및 캐시 활용도 균형 맞추기
Google 검색팀은 여러 구성 옵션을 테스트한 결과 다음 설정이 최신성 및 캐시 활용도 간에 적절한 균형을 제공한다는 사실을 발견했습니다.
서비스 워커 스크립트 URL은 Cache-Control: private, max-age=1500
(1, 500초 또는 25분) 응답 헤더와 함께 제공되며, 헤더가 적용되도록 updateViaCache가 'all'로 설정된 상태로 등록됩니다. Google 검색 웹 백엔드는 짐작할 수 있듯이 전 세계에 분산된 대규모 서버 집합으로, 최대한 100% 가동 시간이 필요합니다. 서비스 워커 스크립트의 콘텐츠에 영향을 미치는 변경사항을 배포하는 작업은 롤링 방식으로 이루어집니다.
사용자가 업데이트된 백엔드를 히트한 후 아직 업데이트된 서비스 워커를 수신하지 못한 백엔드를 히트하는 다른 페이지로 빠르게 이동하면 버전 간에 여러 번 전환하게 됩니다. 따라서 마지막 확인 후 25분이 지난 경우에만 업데이트된 스크립트를 확인하도록 브라우저에 지시해도 큰 단점이 없습니다. 이 동작을 선택하면 서비스 워커 스크립트를 동적으로 생성하는 엔드포인트에서 수신하는 트래픽이 크게 줄어듭니다.
또한 서비스 워커 스크립트의 HTTP 응답에 ETag 헤더가 설정되어 있으므로 25분이 지난 후 업데이트 확인이 실행될 때 그동안 배포된 서비스 워커에 업데이트가 없으면 서버가 HTTP 304 응답으로 효율적으로 응답할 수 있습니다.
Google 검색 웹 앱 내의 일부 상호작용은 단일 페이지 앱 스타일 탐색 (예: History API를 통한 탐색)을 사용하지만 대부분의 경우 Google 검색은 '실제' 탐색을 사용하는 기존 웹 앱입니다. 이는 서비스 워커 업데이트 수명 주기를 가속화하는 두 가지 옵션인 clients.claim()
및 skipWaiting()
을 사용하는 것이 효과적이라고 결정한 팀에서 사용됩니다.
Google 검색의 인터페이스를 클릭하면 일반적으로 새 HTML 문서로 이동하게 됩니다. skipWaiting
를 호출하면 업데이트된 서비스 워커가 설치 직후 이러한 새 탐색 요청을 처리할 수 있습니다. 마찬가지로 clients.claim()
를 호출하면 업데이트된 서비스 워커가 서비스 워커 활성화 후 제어되지 않는 열려 있는 Google 검색 페이지를 제어할 수 있습니다.
Google 검색에서 채택한 접근 방식은 반드시 모든 사용자에게 적합한 솔루션은 아닙니다. 가장 효과적인 솔루션을 찾을 때까지 게재 옵션의 다양한 조합을 신중하게 A/B 테스트한 결과입니다.
백엔드 인프라를 통해 업데이트를 더 빠르게 배포할 수 있는 개발자는 항상 HTTP 캐시를 무시하여 브라우저가 업데이트된 서비스 워커 스크립트를 최대한 자주 확인하도록 하는 것이 좋습니다.
사용자가 장시간 열어둘 수 있는 단일 페이지 앱을 빌드하는 경우 skipWaiting()
를 사용하는 것이 적절하지 않을 수 있습니다. 장기 실행 클라이언트가 있는 동안 새 서비스 워커가 활성화되도록 허용하면 캐시 불일치가 발생할 위험이 있습니다.
핵심 요점
기본적으로 서비스 워커는 성능 중립적이지 않습니다.
웹 앱에 서비스 워커를 추가한다는 것은 웹 앱이 요청에 대한 응답을 받기 전에 로드되고 실행되어야 하는 JavaScript를 추가로 삽입하는 것을 의미합니다. 이러한 응답이 네트워크가 아닌 로컬 캐시에서 가져온다면 서비스 워커를 실행하는 오버헤드는 캐시 우선 접근으로 얻는 성능 이점에 비해 일반적으로 무시할 수 있습니다. 하지만 서비스 워커가 탐색 요청을 처리할 때 항상 네트워크에 컨설트해야 한다는 것을 알고 있다면 탐색 미리 로드를 사용하는 것이 중요한 성능 향상 요소가 됩니다.
서비스 워커는 여전히 점진적인 개선사항입니다.
서비스 워커 지원은 1년 전보다 훨씬 더 밝은 전망을 갖고 있습니다. 이제 모든 최신 브라우저에서 서비스 워커를 지원하지만 안타깝게도 백그라운드 동기화 및 탐색 미리 로드와 같은 일부 고급 서비스 워커 기능은 전 세계적으로 출시되지 않았습니다. 필요한 것으로 알고 있는 특정 하위 집합의 기능을 확인하고 이러한 기능이 있는 경우에만 서비스 워커를 등록하는 것이 여전히 합리적인 접근 방식입니다.
마찬가지로 실제 환경에서 실험을 진행한 결과, 저가형 기기에서 서비스 워커의 추가 오버헤드로 인해 성능이 저하된다는 것을 알고 있다면 이러한 시나리오에서도 서비스 워커를 등록하지 않을 수 있습니다.
서비스 워커는 모든 기본 요건이 충족되고 서비스 워커가 사용자 환경과 전반적인 로드 성능에 긍정적인 영향을 미칠 때 웹 앱에 추가되는 점진적 개선으로 계속 간주해야 합니다.
모든 요소 측정
서비스 워커를 출시한 것이 사용자 환경에 긍정적인 영향을 미쳤는지 아니면 부정적인 영향을 미쳤는지 확인하는 유일한 방법은 실험하고 결과를 측정하는 것입니다.
의미 있는 측정을 설정하는 구체적인 방법은 사용 중인 분석 제공업체와 배포 설정에서 일반적으로 실험을 수행하는 방식에 따라 다릅니다. Google 애널리틱스를 사용하여 측정항목을 수집하는 한 가지 접근 방식은 Google I/O 웹 앱에서 서비스 워커를 사용하는 경험을 기반으로 이 케이스 스터디에 자세히 설명되어 있습니다.
비목표
웹 개발 커뮤니티의 많은 사람들이 서비스 워커를 프로그레시브 웹 앱과 연결시키지만 'Google 검색 PWA'를 빌드하는 것이 팀의 초기 목표는 아니었습니다. Google 검색 웹 앱은 현재 웹 앱 매니페스트를 통해 메타데이터를 제공하지 않으며 사용자가 홈 화면에 추가 흐름을 거치도록 권장하지도 않습니다. 현재 검색팀은 Google 검색의 기존 진입점을 통해 웹 앱으로 유입되는 사용자에 만족하고 있습니다.
Google 검색 웹 환경을 설치된 애플리케이션에서 기대할 수 있는 환경으로 전환하기보다는 초기 출시에서는 기존 웹사이트를 점진적으로 개선하는 데 중점을 두었습니다.
감사의 말씀
서비스 워커 구현에 참여하고 이 도움말 작성에 사용된 배경 자료를 공유해 주신 Google 검색 웹 개발팀 전체에 감사드립니다. 필립 골레, 라제시 자간나탄, R. 사무엘 클라치코, 앤디 마르토네, 레오나르도 페냐, 레이첼 셰어러, 그렉 테로노, 클레이 울람
업데이트 (2021년 10월): 이 도움말이 처음 게시된 이후 Google 검색팀은 현재 서비스 워커 아키텍처의 이점과 단점을 재평가했습니다. 위에서 설명한 서비스 워커가 지원 중단됩니다. Google 검색 웹 인프라가 발전함에 따라 서비스 워커 설계가 다시 검토될 수 있습니다.