백그라운드 동기화 소개

Jake Archibald
Jake Archibald

백그라운드 동기화는 사용자가 안정적인 연결을 사용할 때까지 작업을 지연할 수 있는 새로운 웹 API입니다. 이렇게 하면 사용자가 전송하려는 항목이 실제로 전송됩니다.

문제

인터넷은 시간을 낭비하기에 좋은 장소입니다. 인터넷에서 시간을 낭비하지 않으면 고양이가 꽃을 싫어한다는 사실이나 카멜레온이 거품을 좋아한다는 사실, 에릭 비델만90년대 후반의 퍼트 퍼트 골프 영웅이라는 사실을 알 수 없습니다.

하지만 때로는 시간을 낭비하고 싶지 않을 때도 있습니다. 원하는 사용자 환경은 다음과 같습니다.

  1. 휴대전화가 주머니 밖에 있습니다.
  2. 소규모 목표 달성
  3. 휴대전화를 주머니에 넣습니다.
  4. 다시 일상을 시작합니다.

안타깝게도 연결 상태가 좋지 않아 이러한 환경이 자주 중단됩니다. 누구나 겪었을 법한 경험 흰색 화면이나 스피너를 바라보고 있는데 포기하고 다른 일을 해야 한다는 걸 알지만 혹시나 해서 10초만 더 기다려 봅니다. 10초 후에는 어떻게 되나요? 없습니다.

하지만 지금 포기하면 안 됩니다. 이미 시간을 투자했으므로 아무것도 얻지 못하고 떠나기는 아깝기 때문에 계속 기다립니다. 이쯤 되면 포기하고 싶지만 포기하는 순간이 바로 기다렸다면 모든 것이 로드될 순간이라는 것을 알고 있습니다.

서비스 워커는 캐시에서 콘텐츠를 제공하여 페이지 로드 부분을 해결합니다. 하지만 페이지에서 서버로 무언가를 전송해야 하는 경우는 어떻게 해야 하나요?

현재 사용자가 메시지에서 '보내기'를 누르면 전송이 완료될 때까지 스피너를 쳐다봐야 합니다. 사용자가 탭을 닫거나 다른 탭으로 이동하려고 하면 onbeforeunload를 사용하여 '아니요, 이 스피너를 좀 더 봐야 합니다. 죄송합니다." 사용자가 연결되어 있지 않으면 '죄송합니다. 나중에 다시 방문하여 다시 시도해 주세요'라고 안내합니다.

헛소리입니다. 백그라운드 동기화를 사용하면 더 나은 결과를 얻을 수 있습니다.

해결 방법

다음 동영상에서는 그림 이모티콘 전용 채팅 데모인 Emojoy를 보여줍니다. 프로그레시브 웹 앱이며 오프라인 우선으로 작동합니다. 앱이 푸시 메시지와 알림을 사용하고 백그라운드 동기화를 사용합니다.

사용자가 연결 상태가 없을 때 메일을 보내려고 하면 연결이 되면 메일이 백그라운드에서 전송됩니다.

2016년 3월부터 Chrome 버전 49 이상에서 백그라운드 동기화를 사용할 수 있습니다. 다음 단계에 따라 작동하는 모습을 확인할 수 있습니다.

  1. Emojoy를 엽니다.
  2. 비행기 모드를 사용하거나 로컬 패러데이 새장을 방문하여 오프라인으로 전환합니다.
  3. 메시지를 입력합니다.
  4. 홈 화면으로 돌아갑니다 (원하는 경우 탭 또는 브라우저를 닫음).
  5. 온라인 상태로 전환합니다.
  6. 메시지가 백그라운드에서 전송됩니다.

이렇게 백그라운드에서 전송할 수 있으면 인식되는 성능도 개선됩니다. 앱은 메시지 전송에 대해 크게 신경 쓸 필요가 없으므로 메시지를 출력에 바로 추가할 수 있습니다.

백그라운드 동기화를 요청하는 방법

이 기능은 진정한 확장 가능한 웹 스타일로, 필요한 작업을 자유롭게 실행할 수 있는 하위 수준 기능입니다. 사용자에게 연결이 있으면 이벤트가 실행되도록 요청합니다. 사용자가 이미 연결되어 있으면 즉시 실행됩니다. 그런 다음 해당 이벤트를 수신 대기하고 필요한 작업을 실행합니다.

푸시 메시지와 마찬가지로 페이지가 열려 있지 않아도 작동할 수 있도록 서비스 워커를 이벤트 타겟으로 사용합니다. 시작하려면 페이지에서 동기화를 등록합니다.

// Register your service worker:
navigator.serviceWorker.register('/sw.js');

// Then later, request a one-off sync:
navigator.serviceWorker.ready.then(function(swRegistration) {
  return swRegistration.sync.register('myFirstSync');
});
 ```

Then listen for the event in `/sw.js`:

```js
self.addEventListener('sync', function(event) {
  if (event.tag == 'myFirstSync') {
    event.waitUntil(doSomeStuff());
  }
});

이상입니다 위에서 doSomeStuff()는 수행하려는 작업의 성공/실패를 나타내는 약속을 반환해야 합니다. 약속이 처리되면 동기화가 완료됩니다. 실패하면 다시 시도할 동기화가 예약됩니다. 동기화 재시도도 연결을 기다리고 지수 백오프를 사용합니다.

동기화의 태그 이름(위 예에서는 'myFirstSync')은 특정 동기화에 대해 고유해야 합니다. 대기 중인 동기화와 동일한 태그를 사용하여 동기화를 등록하면 기존 동기화와 병합됩니다. 즉, 사용자가 메시지를 보낼 때마다 '받은편지함 지우기' 동기화를 등록할 수 있지만, 오프라인 상태에서 메시지를 5개 보낸 경우 사용자가 온라인 상태가 되면 동기화가 한 번만 실행됩니다. 5개의 별도 동기화 이벤트를 원한다면 고유한 태그를 사용하면 됩니다.

최소한의 작업을 실행하는 간단한 데모는 동기화 이벤트를 사용하여 알림을 표시합니다.

백그라운드 동기화는 어디에 사용할 수 있나요?

페이지의 수명 주기 이후에 중요한 데이터 전송을 예약하는 데 사용하는 것이 좋습니다. 채팅 메시지, 이메일, 문서 업데이트, 설정 변경사항, 사진 업로드 등 사용자가 탭을 닫거나 탐색을 종료하더라도 서버에 전송하려는 모든 항목 페이지는 indexedDB의 '보관함' 저장소에 이를 저장할 수 있으며 서비스 워커는 이를 검색하여 전송합니다.

소량의 데이터를 가져오는 데도 사용할 수 있습니다.

또 다른 데모입니다.

페이지 로드 속도 향상을 위해 만든 오프라인 위키백과 데모입니다. 그 이후로 백그라운드 동기화 마법을 추가했습니다.

직접 사용해 보세요. Chrome 49 이상을 사용 중인지 확인한 다음 다음 단계를 따르세요.

  1. Chrome과 같은 도움말로 이동합니다.
  2. 비행기 모드를 사용하거나 저처럼 불량한 모바일 제공업체를 이용하여 오프라인으로 전환합니다.
  3. 다른 도움말 링크를 클릭합니다.
  4. 페이지를 로드할 수 없다는 메시지가 표시됩니다 (페이지를 로드하는 데 시간이 걸리는 경우에도 이 메시지가 표시됨).
  5. 알림에 동의합니다.
  6. 브라우저를 닫습니다.
  7. 온라인 전환
  8. 도움말이 다운로드되고 캐시되어 볼 준비가 되면 알림이 전송됩니다.

이 패턴을 사용하면 사용자는 휴대전화를 주머니에 넣고 원하는 항목을 가져왔을 때 휴대전화에서 알림을 보내준다는 사실을 알고 일상생활을 계속할 수 있습니다.

권한

제가 보여드린 데모에서는 권한이 필요한 웹 알림을 사용하지만 백그라운드 동기화 자체는 권한이 필요하지 않습니다.

동기화 이벤트는 사용자가 사이트의 페이지를 열어 있는 동안 완료되는 경우가 많으므로 사용자 권한을 요구하면 사용자 환경이 저하될 수 있습니다. 대신 악용을 방지하기 위해 동기화가 등록되고 트리거될 수 있는 시점을 제한하고 있습니다. 예를 들면 다음과 같습니다.

  • 동기화 이벤트는 사용자가 사이트 창을 열어 두었을 때만 등록할 수 있습니다.
  • 이벤트 실행 시간은 제한되어 있으므로 이를 사용하여 x초마다 서버에 핑을 보내거나 비트코인을 채굴하는 등의 작업을 할 수 없습니다.

물론 이러한 제한은 실제 사용량에 따라 완화되거나 강화될 수 있습니다.

점진적 개선

특히 Safari와 Edge에서 아직 서비스 워커를 지원하지 않으므로 모든 브라우저에서 백그라운드 동기화를 지원하기까지는 시간이 걸릴 것입니다. 하지만 점진적 개선을 사용하면 다음과 같은 이점이 있습니다.

if ('serviceWorker' in navigator && 'SyncManager' in window) {
  navigator.serviceWorker.ready.then(function(reg) {
    return reg.sync.register('tag-name');
  }).catch(function() {
    // system was unable to register for a sync,
    // this could be an OS-level restriction
    postDataFromThePage();
  });
} else {
  // serviceworker/sync not supported
  postDataFromThePage();
}

서비스 워커 또는 백그라운드 동기화를 사용할 수 없는 경우 지금과 같이 페이지에서 콘텐츠를 게시하면 됩니다.

사용자의 연결 상태가 양호한 것처럼 보이더라도 백그라운드 동기화를 사용하는 것이 좋습니다. 데이터 전송 중에 탐색 및 탭 닫힘으로부터 보호할 수 있기 때문입니다.

앞으로

Google은 2016년 상반기에 백그라운드 동기화를 Chrome의 안정화 버전에 제공하는 동시에 '주기적 백그라운드 동기화'라는 변형을 개발하고 있습니다. 주기적 백그라운드 동기화를 사용하면 시간 간격, 배터리 상태, 네트워크 상태로 제한된 이벤트를 요청할 수 있습니다. 물론 사용자 권한이 필요하며 이러한 이벤트가 실행되는 시점과 빈도는 브라우저에 따라 다릅니다. 즉, 뉴스 사이트에서 매시간 동기화를 요청할 수 있지만 브라우저는 사용자가 07:00에만 해당 사이트를 읽는다는 것을 알 수 있으므로 매일 06:50에 동기화가 실행됩니다. 이 아이디어는 일회성 동기화보다 조금 더 먼 얘기지만, 곧 제공될 예정입니다.

Google은 웹의 장점을 유지하면서 Android 및 iOS에서 성공적인 패턴을 웹에 점진적으로 도입하고 있습니다.