서비스 워커 등록

서비스 워커 등록 시점 권장사항

서비스 워커는 웹 앱 재방문 속도를 크게 높일 수 있지만, 서비스 워커의 초기 설치가 사용자의 첫 방문 환경을 저하시키지 않도록 조치를 취해야 합니다.

일반적으로 초기 페이지가 로드된 후에 서비스 워커 등록을 지연하면 특히 네트워크 연결 속도가 느린 휴대기기 사용자에게 최상의 환경을 제공할 수 있습니다.

일반적인 등록 상용구

서비스 워커에 관해 읽어본 적이 있다면 다음과 매우 유사한 템플릿을 접했을 것입니다.

if ('serviceWorker' in navigator) {
    navigator.serviceWorker.register('/service-worker.js');
}

경우에 따라 사용자에게 페이지를 새로고침하라는 메시지를 전달하기 위해 몇 개의 console.log() 문이 포함되거나 이전 서비스 워커 등록의 업데이트를 감지하는 코드가 포함될 수 있습니다. 하지만 이는 표준 코드 몇 줄의 사소한 변형일 뿐입니다.

navigator.serviceWorker.register에는 어떤 뉘앙스가 있나요? 따를 만한 권장사항이 있나요? 이 도움말이 여기서 끝나지 않는다는 점을 감안할 때 놀랍지 않게도 두 질문에 대한 답변은 모두 '예'입니다.

사용자의 첫 방문

사용자가 웹 앱을 처음 방문하는 경우를 생각해 보겠습니다. 아직 서비스 워커가 없으며 브라우저는 결국 설치될 서비스 워커가 있는지 사전에 알 수 있는 방법이 없습니다.

개발자는 브라우저가 대화형 페이지를 표시하는 데 필요한 최소한의 중요 리소스 세트를 빠르게 가져오도록 하는 것이 가장 중요합니다. 이러한 응답을 가져오는 속도를 저하시키는 요소는 빠른 양방향 환경을 제공하는 데 방해가 됩니다.

이제 페이지에서 렌더링해야 하는 JavaScript 또는 이미지를 다운로드하는 과정에서 브라우저가 백그라운드 스레드 또는 프로세스를 시작하기로 결정했다고 가정해 보겠습니다 (간단히 하기 위해 스레드라고 가정). 강력한 데스크톱 머신이 아니라 전 세계 많은 사용자가 기본 기기로 사용하는 저사양 휴대전화를 사용하고 있다고 가정해 보겠습니다. 이 추가 스레드를 시작하면 브라우저에서 대화형 웹페이지 렌더링에 사용할 수 있는 CPU 시간과 메모리에 대한 경합이 발생합니다.

유휴 백그라운드 스레드는 큰 차이를 만들지 않을 수 있습니다. 하지만 이 스레드가 유휴 상태가 아니고 대신 네트워크에서 리소스 다운로드를 시작한다고 결정하면 어떻게 될까요? CPU 또는 메모리 경합에 대한 우려는 많은 휴대기기에서 사용할 수 있는 제한된 대역폭에 대한 우려에 비해 우선순위가 낮습니다. 대역폭은 소중하므로 보조 리소스를 동시에 다운로드하여 중요한 리소스를 손상시키지 마세요.

즉, 백그라운드에서 리소스를 다운로드하고 캐시하기 위해 새 서비스 워커 스레드를 시작하면 사용자가 사이트를 처음 방문할 때 가장 짧은 상호작용 시간 환경을 제공한다는 목표에 역효과를 줄 수 있습니다.

템플릿 개선

해결 방법은 navigator.serviceWorker.register()를 호출할 시점을 선택하여 서비스 워커의 시작을 제어하는 것입니다. 간단한 규칙은 다음과 같이 window에서 load event이 실행된 후에 등록을 지연하는 것입니다.

if ('serviceWorker' in navigator) {
    window.addEventListener('load', function() {
    navigator.serviceWorker.register('/service-worker.js');
    });
}

하지만 서비스 워커 등록을 시작할 적절한 시점은 웹 앱이 로드된 직후 웹 앱에서 실행하는 작업에 따라 달라질 수 있습니다. 예를 들어 Google I/O 2016 웹 앱에는 기본 화면으로 전환하기 전에 짧은 애니메이션이 표시됩니다. 애니메이션 중에 서비스 워커 등록을 시작하면 저가형 휴대기기에서 버벅거림이 발생할 수 있다는 사실이 확인되었습니다. 사용자에게 나쁜 환경을 제공하는 대신 애니메이션이 끝난 후 브라우저가 몇 초 동안 유휴 상태일 가능성이 가장 높은 시점까지 서비스 워커 등록을 지연했습니다.

마찬가지로 웹 앱에서 페이지가 로드된 후 추가 설정을 실행하는 프레임워크를 사용하는 경우 작업이 완료되었음을 알리는 프레임워크별 이벤트를 찾습니다.

후속 방문

지금까지는 첫 방문 환경에 중점을 두었지만 서비스 워커 등록 지연이 사이트 재방문에 어떤 영향을 미치나요? 일부 사용자에게는 놀라운 소식일 수 있지만 전혀 영향을 미치지 않습니다.

서비스 워커가 등록되면 installactivate 수명 주기 이벤트를 거칩니다. 서비스 워커가 활성화되면 이후 웹 앱 방문에 대한 fetch 이벤트를 처리할 수 있습니다. 서비스 워커는 범위 내 페이지에 대한 요청이 이루어지기 전에 시작됩니다. 이는 당연한 일입니다. 페이지를 방문하기 전에 기존 서비스 워커가 아직 실행되지 않았다면 탐색 요청에 대한 fetch 이벤트를 처리할 기회가 없습니다.

따라서 활성 서비스 워커가 있으면 navigator.serviceWorker.register()를 호출하는 시점이나 실제로 호출 여부는 중요하지 않습니다. 서비스 워커 스크립트의 URL을 변경하지 않는 한 navigator.serviceWorker.register()는 후속 방문 중에 사실상 무작위 작업입니다. 호출 시점은 중요하지 않습니다.

사전 등록해야 하는 이유

서비스 워커를 최대한 빨리 등록하는 것이 적절한 시나리오가 있나요? 예를 들어 서비스 워커가 첫 방문 중에 clients.claim()를 사용하여 페이지를 제어하고 서비스 워커가 fetch 핸들러 내부에서 런타임 캐싱을 적극적으로 실행하는 경우를 들 수 있습니다. 이 경우 서비스 워커를 최대한 빨리 활성화하여 나중에 유용할 수 있는 리소스로 런타임 캐시를 채우는 것이 좋습니다. 웹 앱이 이 카테고리에 속하는 경우 한 걸음 물러나 서비스 워커의 install 핸들러가 기본 페이지의 요청과 대역폭을 놓고 경쟁하는 리소스를 요청하지 않는지 확인하는 것이 좋습니다.

테스트

첫 방문을 시뮬레이션하는 좋은 방법은 Chrome 시크릿 창에서 웹 앱을 열고 Chrome의 DevTools에서 네트워크 트래픽을 확인하는 것입니다. 웹 개발자는 하루에 수십 번 웹 앱의 로컬 인스턴스를 새로고침합니다. 하지만 이미 서비스 워커가 있고 캐시가 완전히 채워진 상태에서 사이트를 다시 방문하면 신규 사용자가 경험하는 것과 동일한 환경을 경험할 수 없으며 잠재적인 문제를 쉽게 무시할 수 있습니다.

다음은 등록 시점의 차이를 보여주는 예입니다. 두 스크린샷 모두 네트워크 제한을 사용하여 느린 연결을 시뮬레이션하는 시크릿 모드에서 샘플 앱을 방문하는 동안 찍은 것입니다.

조기 등록이 포함된 네트워크 트래픽

위의 스크린샷은 최대한 빨리 서비스 워커 등록을 실행하도록 샘플이 수정되었을 때의 네트워크 트래픽을 반영합니다. 페이지를 표시하는 데 필요한 다른 리소스에 대한 요청과 함께 미리 캐시 요청 (서비스 워커의 install 핸들러에서 발생하며 옆에 기어 아이콘이 있는 항목)이 삽입되어 있는 것을 볼 수 있습니다.

등록이 지연된 네트워크 트래픽

위 스크린샷에서 서비스 워커 등록은 페이지가 로드된 후에 지연되었습니다. 모든 리소스가 네트워크에서 가져와질 때까지 미리 캐시 요청이 시작되지 않으므로 대역폭 경합이 제거됩니다. 또한 미리 캐시하는 일부 항목은 이미 브라우저의 HTTP 캐시에 있으므로(크기 열에 (from disk cache)가 있는 항목) 네트워크로 다시 이동하지 않고도 서비스 워커의 캐시를 채울 수 있습니다.

실제 모바일 네트워크에서 실제 저가형 기기로 이러한 테스트를 실행하면 보너스 점수를 받을 수 있습니다. Chrome의 원격 디버깅 기능을 활용하여 Android 휴대전화를 USB를 통해 데스크톱 컴퓨터에 연결하고 실행 중인 테스트가 실제로 많은 사용자의 실제 환경을 반영하는지 확인할 수 있습니다.

결론

요약하자면 사용자에게 최상의 첫 방문 경험을 제공하는 것이 가장 중요합니다. 초기 방문 중에 페이지가 로드된 후에 서비스 워커 등록을 지연하면 이를 보장할 수 있습니다. 재방문 시 서비스 워커의 모든 이점을 계속 누릴 수 있습니다.

첫 번째 페이지가 로드될 때까지 서비스 워커의 초기 등록을 지연시키는 간단한 방법은 다음을 사용하는 것입니다.

if ('serviceWorker' in navigator) {
    window.addEventListener('load', function() {
    navigator.serviceWorker.register('/service-worker.js');
    });
}