서비스 워커 등록 타이밍의 모범 사례
서비스 워커는 웹 앱의 반복 방문 속도를 크게 높일 수 있지만 서비스 워커의 초기 설치가 사용자의 첫 방문 환경을 저하시키지 않도록 조치를 취해야 합니다.
일반적으로 초기 페이지가 로드된 후까지 서비스 워커 등록을 지연하면 사용자, 특히 네트워크 연결이 느린 휴대기기 사용자에게 최상의 환경을 제공할 수 있습니다.
일반적인 등록 상용구
서비스 워커에 대한 정보를 읽은 적이 있다면 아마 다음과 유사한 상용구를 본 적이 있을 것입니다.
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/service-worker.js');
}
여기에는 사용자에게 페이지 새로고침을 알리는 방법으로 몇 가지 console.log()
문 또는 이전 서비스 워커 등록에 대한 업데이트를 감지하는 코드가 수반될 수 있습니다. 그러나 이는 표준 코드 몇 줄을 살짝 바꾼 것에 불과합니다.
navigator.serviceWorker.register
는 무엇이 다를까요? 따라야 할 권장사항이 있나요? 이 글이 여기서 끝나지 않는 다는 점을 감안하면 이 두 질문에 대한 대답이 '예'라는 것은 당연한 일입니다.
사용자의 첫 방문
사용자가 웹 앱을 처음 방문했다고 가정해 보겠습니다. 아직 서비스 워커가 없으며 브라우저는 나중에 서비스 워커가 설치될지 미리 알 수 없습니다.
개발자로서 여러분은 상호작용이 가능한 페이지를 표시하는 데 필요한 최소한의 중요한 리소스 집합을 브라우저가 신속하게 가져오도록 해야 합니다. 이러한 응답을 가져오는 속도를 저하시키는 모든 것은 신속한 상호작용까지의 시간(time-to-interactive) 제공의 적입니다.
이제 페이지가 렌더링해야 하는 자바스크립트 또는 이미지를 다운로드하는 과정에서 브라우저가 백그라운드 스레드 또는 프로세스를 시작하기로 결정했다고 상상해봅시다 (단순화하기 위해 스레드라고 가정함). 강력한 데스크톱 컴퓨터가 아니라 세상 사람들 대부분이 자신의 기본 기기라고 생각하는 저전력 휴대폰 유형을 사용하고 있다고 가정해봅시다. 이 추가 스레드를 구동하면 브라우저가 상호작용이 가능한 웹페이지를 렌더링하는 데 소비할 수 있는 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 웹 앱은 기본 화면으로 전환하기 전에 짧은 애니메이션을 제공합니다. Google팀은 애니메이션 중 서비스 워커 등록을 시작하면 저사양 휴대기기에서 버벅거림이 발생할 수 있다는 사실을 확인했습니다. 사용자에게 나쁜 경험을 제공하는 대신에 브라우저가 몇 초 동안 유휴 상태가 될 가능성이 가장 높은 애니메이션 이후까지 서비스 워커 등록을 지연했습니다.
마찬가지로, 웹 앱에서 페이지가 로드된 후 추가 설정을 수행하는 프레임워크를 사용하는 경우에도 해당 작업의 완료를 알리는 프레임워크별 이벤트를 찾으면 됩니다.
후속 방문
지금까지 첫 번째 방문 경험에 중점을 두었는데, 서비스 워커 등록을 지연하면 사이트를 다시 방문할 때 어떤 영향이 있을까요? 놀랍게도 어떤 영향도 미치지 않습니다.
서비스 워커가 등록되면 install
및 activate
수명 주기 이벤트를 거칩니다.
서비스 워커가 활성화되면 이후부터 웹 앱을 방문할 때 fetch
이벤트를 처리할 수 있습니다. 서비스 워커는 범위 내에 있는 페이지의 요청이 있기 전에 시작합니다. 그 이유는 생각해보면 이해가 될 것입니다. 기존 서비스 워커가 페이지를 방문하기 전에 이미 실행 중이 아니었다면 탐색 요청에 대한 fetch
이벤트를 실행할 기회가 없을 것입니다.
따라서 활성화된 서비스 워커가 있는 경우 navigator.serviceWorker.register()
호출 시간 또는 호출 여부는 전혀 중요하지 않습니다.
서비스 워커 스크립트의 URL을 변경하지 않는 한 navigator.serviceWorker.register()
는 후속 방문 중에 사실상 무작동합니다. 호출 시간은 관련이 없습니다.
일찍 등록해야 하는 이유
서비스 워커를 가급적 일찍 등록하는 것이 좋은 경우에 해당하는 시나리오가 있을까요? 예를 들면, 서비스 워커가 첫 번째 방문 중에 clients.claim()
를 사용하여 페이지를 제어하고 서비스 워커가 fetch
핸들러 내부에서 런타임 캐싱을 적극적으로 실행하는 경우가 이에 해당합니다. 이러한 상황에서는 서비스 워커를 최대한 빨리 활성화하고 나중에 유용할 수 있는 리소스로 런타임 캐시를 채우면 도움이 됩니다. 웹 앱이 이 범주에 해당하는 경우 서비스 워커의 install
핸들러가 기본 페이지의 요청과 대역폭을 놓고 경쟁하는 리소스를 요청하지 않도록 미리 조치를 취하는 것이 좋습니다.
테스트
첫 방문을 시뮬레이션하는 가장 좋은 방법은 Chrome 시크릿 창에서 웹 앱을 열고 Chrome DevTools에서 네트워크 트래픽을 확인하는 것입니다. 웹 개발자는 아마도 웹 앱의 로컬 인스턴스를 하루에도 수십 번 다시 로드할 것입니다. 그러나 서비스 워커와 완전히 채워진 캐시가 이미 있을 때 사이트를 다시 방문하면 신규 사용자가 얻을 수 있는 것과 동일한 경험을 얻을 수 없으며 잠재적인 문제를 무시하기 쉽습니다.
다음은 등록 타이밍에 따른 차이점을 보여주는 예시입니다. 다음 두 스크린샷은 시크릿 모드에서 샘플 앱을 방문하는 동안 네트워크 제한을 통해 느린 연결을 시뮬레이션하여 촬영했습니다.
위의 스크린샷은 서비스 워커 등록을 가급적 빨리 수행하도록 샘플을 수정한 경우의 네트워크 트래픽을 반영합니다. 페이지를 표시하는 데 필요한 다른 리소스에 대한 요청이 섞여 있는 사전 캐싱 요청 (서비스 워커의 install
핸들러에서 나온, 톱니바퀴 아이콘이 옆에 표시된 항목)을 볼 수 있습니다.
위의 스크린샷에서 서비스 워커 등록은 페이지가 로드된 이후까지 지연되었습니다. 네트워크에서 모든 리소스를 가져올 때까지 사전 캐싱 요청은 시작되지 않고 대역폭에 대한 경쟁을 제거한 상태임을 확인할 수 있습니다. 또한 사전 캐싱을 시도할 항목 중 일부는 브라우저의 HTTP 캐시(Size 열에 (from disk cache)
가 있는 항목)에 이미 있기 때문에 네트워크로 다시 이동하지 않고 서비스 워커의 캐시를 채울 수 있습니다.
실제 모바일 네트워크의 실제 저급 기기에서 이러한 종류의 테스트를 실행하면 보너스 점수를 받을 수 있습니다. Chrome의 원격 디버깅 기능을 활용하여 USB를 통해 Android 스마트폰을 데스크톱 컴퓨터에 연결하고 실행 중인 테스트가 많은 사용자의 실제 세계 경험을 실제로 반영하도록 보장할 수 있습니다.
결론
요컨대, 사용자의 첫 번째 방문이 좋은 경험이 되도록 보장하는 작업을 최우선시해야 합니다. 첫 번째 방문 동안 페이지가 로드된 이후까지 서비스 워커 등록을 지연하면 이렇게 하는 데 도움이 될 수 있습니다. 재방문 동안에도 서비스 워커의 모든 이점을 누리게 됩니다.
첫 번째 페이지가 로드된 이후까지 서비스 워커의 초기 등록을 지연하는 간단한 방법은 다음을 사용하는 것입니다.
if ('serviceWorker' in navigator) {
window.addEventListener('load', function() {
navigator.serviceWorker.register('/service-worker.js');
});
}