서비스 워커(Service Worker)란?
No Filled
웹 페이지와 별도로 브라우저 백그라운드에서 실행되는 JavaScript 스크립트로, 네트워크 요청을 가로채어 오프라인 경험과 백그라운드 동기화를 가능하게 하는 기술
기본 개념
- 웹 애플리케이션, 브라우저, 네트워크 사이에 위치한 프록시 서버 역할을 하는 스크립트
- DOM에 직접 접근할 수 없으며, 독립적인 워커 컨텍스트에서 실행
등장 배경
- 문제점: 기존 웹은 네트워크 연결이 끊기면 사용 불가능
- AppCache의 한계: 이전 오프라인 솔루션인 AppCache는 유연성 부족, 예측 불가능한 동작
- 네이티브 앱과의 격차: 푸시 알림, 백그라운드 동기화 등 네이티브 앱 기능 부재
- 해결: 개발자가 네트워크 요청을 완전히 제어할 수 있는 프로그래밍 가능한 프록시 제공
동작 원리
1단계: 등록
- 메인 스크립트에서
navigator.serviceWorker.register()호출 - 브라우저가 서비스 워커 파일 다운로드 시작
2단계: 설치
- 처음 등록되거나 새 버전이 발견될 때 발생
install이벤트에서 정적 자산 캐싱
3단계: 활성화
- 이전 버전 정리 작업 수행
- 오래된 캐시 삭제
4단계: 제어
- 페이지의 네트워크 요청 가로채기
- 캐시 우선, 네트워크 우선 등 전략 구현
관련 개념과 비교
Web Worker
- Web Worker: 복잡한 연산 처리용, 페이지와 생명주기 동일
- Service Worker: 네트워크 프록시, 페이지 종료 후에도 생존 가능
AppCache
- AppCache: 선언적, 제한적, deprecated
- Service Worker: 프로그래밍 방식, 완전한 제어 가능
코드 예시
서비스 워커 등록
// HTTPS 환경에서만 동작 (localhost 제외)
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker
.register('/service-worker.js')
.then((registration) => {
console.log('SW 등록 성공:', registration.scope)
})
.catch((error) => {
console.log('SW 등록 실패:', error)
})
})
}서비스 워커 파일
const CACHE_NAME = 'my-app-v1'
const urlsToCache = ['/', '/styles/main.css', '/scripts/app.js', '/images/logo.png']
// 설치 단계: 정적 자산 캐싱
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(CACHE_NAME).then((cache) => {
console.log('캐시 열림')
return cache.addAll(urlsToCache)
}),
)
// 즉시 활성화 (개발 시)
self.skipWaiting()
})
// 활성화 단계: 오래된 캐시 삭제
self.addEventListener('activate', (event) => {
event.waitUntil(
caches.keys().then((cacheNames) => {
return Promise.all(
cacheNames.map((cacheName) => {
if (cacheName !== CACHE_NAME) {
console.log('오래된 캐시 삭제:', cacheName)
return caches.delete(cacheName)
}
}),
)
}),
)
// 모든 클라이언트 즉시 제어
self.clients.claim()
})
// Fetch 단계: Cache First 전략
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request).then((response) => {
// 캐시에 있으면 반환, 없으면 네트워크 요청
return response || fetch(event.request)
}),
)
})Network First 전략
// API 요청에 적합한 Network First 전략
self.addEventListener('fetch', (event) => {
if (event.request.url.includes('/api/')) {
event.respondWith(
fetch(event.request)
.then((response) => {
// 성공 시 캐시에 저장
const responseClone = response.clone()
caches.open(CACHE_NAME).then((cache) => {
cache.put(event.request, responseClone)
})
return response
})
.catch(() => {
// 네트워크 실패 시 캐시 반환 (오프라인 대비)
return caches.match(event.request)
}),
)
}
})헷갈리기 쉬운 부분
Service Worker ≠ Web Worker
- Service Worker: 네트워크 프록시, 페이지와 독립적 생명주기
- Web Worker: 계산 작업용, 페이지 종료 시 함께 종료
개념 정리
서비스 워커는 웹 애플리케이션과 네트워크 사이에서 프록시 역할을 하는 백그라운드 스크립트입니다.
주요 특징으로 페이지와 별도로 백그라운드에서 실행되며 DOM에 직접 접근할 수 없습니다. 그리고 네트워크 요청을 가로채서 캐싱 전략을 구현할 수 있어 오프라인 경험을 제공할 수 있습니다.
생명주기는 등록, 설치, 활성화, 제어의 4단계로 진행됩니다. 등록 시 브라우저가 서비스 워커 파일을 다운로드하고, 설치 단계에서 정적 자산을 캐싱합니다. 활성화 단계에서는 이전 버전의 캐시를 정리하고 이후 fetch 이벤트를 통해 네트워크 요청을 제어합니다.
PWA를 구현할 때 핵심 기술로 사용됩니다. 특히 Cache First 전략으로 정적 자산을 빠르게 제공하고 Network First 전략으로 API 응답의 최신성을 보장하면서도 오프라인 대비책을 마련할 수 있습니다.
보안상 HTTPS 환경에서만 동작하며 개발 시에는 localhost가 예외로 허용됩니다.
핵심 문장
- 서비스 워커는 웹과 네트워크 사이의 프록시로 동작하는 백그라운드 스크립트
- 네트워크 요청을 가로채서 캐싱을 제어 가능
- 오프라인 경험과 빠른 로딩 속도를 제공
- PWA의 핵심 기술
- 등록-설치-활성화-제어의 생명주기
- HTTPS에서만 동작