Navigator: sendBeacon() 메서드

navigator.sendBeacon() 메서드는 적은 양의 데이터를 포함하는 HTTP POST 요청을 비동기적으로 웹 서버에 보냅니다.

XMLHttpRequest 같은 오래된 기술로 웹 서버에 분석 정보를 전송할 때 생길 수 있는 일부 문제를 피하기 위해 고안됐습니다.

참고: 요청을 POST 외의 다른 메서드로 보내야 하거나, 어떤 요청 속성을 바꾸어서 보내야 하거나, 서버로부터의 응답을 받아야 하면 fetch()keepalivetrue로 설정한 것을 대신 사용하세요.

구문

js
sendBeacon(url)
sendBeacon(url, data)

매개변수

url

data 를 받을 서버의 URL 입니다. 상대 주소와 절대 주소 모두 가능합니다.

data Optional

ArrayBuffer, TypedArray, DataView, Blob, 문자열 또는 객체 리터럴, FormData, URLSearchParams 등, 전송할 데이터를 담은 객체입니다.

반환 값

sendBeacon() 메서드는 사용자 에이전트가 전송할 data를 대기열에 성공적으로 추가하면 true를 반환하고, 아니면 false를 반환합니다.

설명

이 메서드는 분석 정보나 진단 데이터를 서버에 보내기 위해 고안됐습니다.

많은 경우, 사이트에서 분석/진단 데이터 전송을 바라는 시점은 사용자가 다른 페이지로 이동할 때처럼 이탈 순간입니다. 기존 방법으로 분석 정보를 보낼 때의 문제는, 이탈 시 전송의 경우 페이지가 언로딩되기 직전인 순간일 수도 있으므로, 브라우저가 재량에 따라 비동기적인 XMLHttpRequest 요청을 보내지 않을 수도 있다는 점입니다.

과거 웹 페이지들은 데이터를 모두 보낼 수 있을 정도로 페이지의 언로딩을 지연시키기도 했습니다. 정확히는 아래와 같은 기법이 있었습니다.

  • 블로킹하도록 동기적 XMLHttpRequest로 데이터 전송
  • <img> 태그를 만들고 src를 설정하기. 대부분의 사용자 에이전트는 이미지를 로드하기 위해 페이지 언로드를 미룹니다.
  • 의미 없는 무한 반복 루프를 몇 초동안 실행하기.

이러한 방법들은 모두 문서의 언로딩을 막으므로 다음 페이지로의 탐색 속도가 저하됩니다. 다음 페이지에는 이를 피하기 위해 할 수 있는 게 없습니다. 따라서 성능 문제는 이전 페이지에 있는데도 새로운 페이지가 느리게 느껴질 것입니다.

sendBeacon() 메서드를 사용하면, 언로딩이나 다음 탐색 지연 없이, 사용자 에이전트가 적절한 순간에 데이터를 비동기적으로 전송합니다. 따라서...

  • 데이터가 안정적으로 전송됨
  • 비동기적임
  • 다음 페이지에 영향을 끼치지 않음

데이터는 HTTP POST 요청으로 보내집니다.

세션 끝에서 분석 정보 보내기

웹 사이트는 대개 사용자가 페이지에서 이탈할 때 진단이나 분석 정보를 보내고자 합니다. 가장 안정적인 방법은 visibilitychange 이벤트에서 데이터를 전송하는 것입니다.

js
document.addEventListener("visibilitychange", function logData() {
  if (document.visibilityState === "hidden") {
    navigator.sendBeacon("/log", analyticsData);
  }
});

unload와 beforeunload 지양

과거에는 많은 웹 사이트들이 세션 끝에 분석 정보를 보내기 위한 용도로 unloadbeforeunload를 사용했습니다. 그러나 이 방법은 극히 불안정합니다. 많은 경우, 특히 모바일에서, 브라우저는 unload, beforeunload, pagehide 등의 이벤트들을 전송하지 않습니다. 예를 들어, 아래의 세 경우에는 이 이벤트들을 수신할 수 없습니다.

  1. 사용자가 페이지를 불러오고 상호작용합니다.
  2. 사용자가 이탈할 때, 탭을 닫지 않고 다른 앱으로 전환합니다.
  3. 사용자가 나중에 기기의 앱 관리자를 통해 브라우저를 닫습니다.

추가적으로, unload 이벤트는 최신 브라우저들에서 구현된 뒤로/앞으로 캐시(bfcache)와 호환되지 않습니다. Firefox를 포함한 일부 브라우저들에서는 unload 이벤트 처리기가 포함되어 있는 페이지를 bfcache에서 제외함으로써 호환성 문제를 해소하므로, 성능이 저하됩니다. Safari와 Chrome 등 나머지 브라우저들은 사용자가 하나의 탭에서 다른 페이지로 탐색하는 경우 unload 이벤트를 아예 전송하지 않습니다.

Firefox는 beforeunload 처리기로도 페이지를 bfcache에서 제외합니다.

pagehide를 대비책으로 사용하기

visibilitychange를 지원하지 않는 브라우저들을 지원하려면 pagehide 이벤트를 사용하세요. beforeunload, unload와 같이 pagehide도 특히 모바일에서 불안정합니다. 하지만 적어도 bfcache와는 호환됩니다.

예제

다음 예제에서는 sendBeacon()을 호출해 분석 정보를 전송하는 visibilitychange 이벤트 처리기를 지정합니다.

js
document.addEventListener("visibilitychange", function logData() {
  if (document.visibilityState === "hidden") {
    navigator.sendBeacon("/log", analyticsData);
  }
});

명세서

Specification
Beacon
# sendbeacon-method

브라우저 호환성

BCD tables only load in the browser

같이 보기

  • visibilitychange 이벤트.
  • Beacon API 개요.
  • Don't lose user and app state, use Page Visibility에서는 왜 beforeunload/unload 대신 visibilitychange를 사용해야 하는지 자세히 설명합니다.
  • Page Lifecycle API에서는 웹 애플리케이션에서 페이지의 수명 주기 동작을 처리하는 최선의 방법들을 제시합니다.
  • PageLifecycle.js: 페이지 수명 주기의 브라우저간 불일치를 처리하기 위한 JavaScript 라이브러리입니다.
  • Back/forward cache. 뒤로/앞으로 캐시가 뭔지, 다양한 페이지 수명 주기 이벤트에서 이 캐시가 갖는 의미가 뭔지 설명합니다.