서비스 워커란?
풍부한 오프라인 경험, 주기적 백그라운드 동기화, 푸쉬 알림이 지원되고 있습니다. 서비스 워커는 이러한 모든 기능의 기술적 기반을 제공합니다. 구글 서비스 워커 설명
따라서 서비스 워커는 백그라운드 동기화, 푸시 알림, 앱 버튼을 클릭해서 앱의 기능들은 앱을 다운로드 받는 방식인 네이티브 앱에서만 가능하다고 여겨지던 것 이었습니다.
그런데, 이제는 설치하지 않고 브라우저에 접속만 하는데도 푸시 알림이 오고 백그라운드 데이터가 자동으로 동기화 된다는 이야기 입니다.
🤓 기존의 웹은 어땠을까?
- 어떤 사용자가 웹 서버에 요청한다.
- 응답으로 HTML, CSS, JavaScript를 받습니다.
- 응답받은 파일을 페이지를 렌더링 한다.
- 이후, JavaScript를 통해 사용자의 요청에 따라 API요청을 해, 필요한 데이터를 받아와서 사용자에게 보여준다.
이와 같은 방식도, 사용자가 웹 페이지를 나가거나 브라우저를 종료하지 않는한, 브라우저 내에서 요청된 JavaScript를 통해 푸시 알림을 보내는 일 같은 것들이 가능합니다.
만약, 사용자가 웹 페이지를 닫았다면 해당 페이지에서 동작하던 JavaScript는 소멸이 되었기 때문에 메시지를 보내고 싶어도 받을 주소가 없기 때문에 응답 자체를 할 수 없습니다.

즉, 브라우저 밖의 요소를 컨트롤 할 수 없다.
😆 그래서, 서비스 워커를 사용한다!
서비스 워커는 브라우저에서 종료 할 때에도 독자적인 형태로 백그라운드에서 실행하는 스크립트이기 때문에 그럴 걱정은 없습니다.
⇒ 즉, 웹 페이지와 별개로 동작한다!
// tslint:disable:no-console // In production, we register a service worker to serve assets from local cache. // This lets the app load faster on subsequent visits in production, and gives // it offline capabilities. However, it also means that developers (and users) // will only see deployed updates on the 'N+1' visit to a page, since previously // cached resources are updated in the background. // To learn more about the benefits of this model, read https://goo.gl/KwvDNy. // This link also includes instructions on opting out of this behavior. const isLocalhost = Boolean( window.location.hostname === 'localhost' || // [::1] is the IPv6 localhost address. window.location.hostname === '[::1]' || // 127.0.0.1/8 is considered localhost for IPv4. window.location.hostname.match( /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ ) ); export default function register() { if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { // The URL constructor is available in all browsers that support SW. const publicUrl = new URL( process.env.PUBLIC_URL!, window.location.toString() ); if (publicUrl.origin !== window.location.origin) { // Our service worker won't work if PUBLIC_URL is on a different origin // from what our page is served on. This might happen if a CDN is used to // serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374 return; } window.addEventListener('load', () => { const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; if (isLocalhost) { // This is running on localhost. Lets check if a service worker still exists or not. checkValidServiceWorker(swUrl); // Add some additional logging to localhost, pointing developers to the // service worker/PWA documentation. navigator.serviceWorker.ready.then(() => { console.log( 'This web app is being served cache-first by a service ' + 'worker. To learn more, visit https://goo.gl/SC7cgQ' ); }); } else { // Is not local host. Just register service worker registerValidSW(swUrl); } }); } } function registerValidSW(swUrl: string) { navigator.serviceWorker .register(swUrl) .then(registration => { registration.onupdatefound = () => { const installingWorker = registration.installing; if (installingWorker) { installingWorker.onstatechange = () => { if (installingWorker.state === 'installed') { if (navigator.serviceWorker.controller) { // At this point, the old content will have been purged and // the fresh content will have been added to the cache. // It's the perfect time to display a 'New content is // available; please refresh.' message in your web app. console.log('New content is available; please refresh.'); } else { // At this point, everything has been precached. // It's the perfect time to display a // 'Content is cached for offline use.' message. console.log('Content is cached for offline use.'); } } }; } }; }) .catch(error => { console.error('Error during service worker registration:', error); }); } function checkValidServiceWorker(swUrl: string) { // Check if the service worker can be found. If it can't reload the page. fetch(swUrl) .then(response => { // Ensure service worker exists, and that we really are getting a JS file. if ( response.status === 404 || response.headers.get('content-type')!.indexOf('javascript') === -1 ) { // No service worker found. Probably a different app. Reload the page. navigator.serviceWorker.ready.then(registration => { registration.unregister().then(() => { window.location.reload(); }); }); } else { // Service worker found. Proceed as normal. registerValidSW(swUrl); } }) .catch(() => { console.log( 'No internet connection found. App is running in offline mode.' ); }); } export function unregister() { if ('serviceWorker' in navigator) { navigator.serviceWorker.ready.then(registration => { registration.unregister(); }); } }
이 코드는 실제로 React 기본 탑제되어 있는 서비스 워커 코드입니다.
서비스워커는 브라우저가 백그라운드에서 실행하는 스크립트이기 때문에 인터넷이 없는 상황에서 브라우저의 캐시를 통해 데이터를 받아와서 보여준것 처럼 할 수 있으며 캐시를 통해 변화를 미리 가져와, 빠른 로딩이 가능하게끔 할 수 있습니다.
이는 웹 서비스와 브라우저 및 네트워크 사이에서 프록시 서버의 역할을 해, 오프라인에서도 사용할 수 있도록 합니다.
😁 서비스 워커의 활용
- 캐시와의 상호작용

만약, 인터넷이 연결이 되어있지 않은 상태에서 브라우저가
fetch
요청을 날렸다면..?서비스워커는
fetch
이벤트의 중간자 역할로 사용할 수 있어, HTTP로 정보를 요청하는대신, 캐시에서 자료를 요청합니다.즉, 네트워크 통신 대신 이벤트의 중간자 역할을 수행하여 캐시에 접근해 요청 데이터가 cache hit라면, 인터넷 없이도 요청된 정보를 받아볼 수 있습니다.
- 푸쉬 알림

브라우저가 닫힌 상태에도 동작하므로, 푸쉬 알림을 구현할 수 있습니다.
- 백그라운드 동기화

채팅 메시지 또는 사진 업로드 등의 작업 도중 오프라인이 되어도, 서비스 워커가 기억하고 있다가 온라인이 되었을 때, 하던 작업을 마저 수행합니다.
😤 서비스 워커의 단점
- 프로세스 동작 중 설치 실패 알림 기능이 부족합니다.
- 인증 정보가 없습니다.
- CORS를 지원하지 않는 리소스에서 URL을 가져올 수 없습니다.
😏 서비스 워커 정리
- 브라우저가 백그라운드에서 실행하는 스크립트이며, 웹페이지와는 다른 라이프 사이클을 가집니다.
- 오프라인일 경우에도 웹 어플리케이션을 기동할 수 있도록 합니다. 간단히 말해, 사용자의 fetch 요청을 가로채, 대신 응답하도록 합니다.
- 보안을 위해 https와 localhost에서만 동작합니다.