[Javascript] 화면 갱신을 하거나 웹페이지를 벗어나려고 할 때 알림창을 표시하는 방법 - beforeunload 이벤트 핸들링

자바스크립트의 "beforeunload" 이벤트를 이용하면 방문자가 화면 갱신을 하려고 하거나 현재 페이지에서 벗어나려고 할 때 저장되지 않은 데이터가 있는지 확인하는 알림을 표시할 수 있습니다.

회원 가입 폼을 작성 중이었거나, 장바구니에서 결제를 하던 도중 벗어날 때, 화면 갱신, 또는 페이지를 벗어날 것인지 확인하는 알림 창을 표시해서 실수로 작성 중이던 데이터를 잃어버리는 일이 없도록 방지할 수 있습니다.

beforeunload 알림창 표시

이 이벤트는 페이지가 정상적으로 닫히는 상태, 즉 사용자 액션에 의해서 다른 페이지로 이동하거나 윈도우가 닫히는 상태에서만 정상 호출되어 실행됩니다. 웹 브라우저 창을 작업 관리자에서 강제 종료하거나, 모바일 기기의 경우 다른 앱으로 이동한 후 앱 관리자에서 앱을 강제 종료하면 이 이벤트는 호출되지 않습니다.

정확하게는 100% 호출을 보장할 수 없다는게 맞지만 이벤트가 발생하기도 하고 안되기도 하는 건 개발의 관점에서는 의미가 없기 때문에 호출되지 않는다고 생각하는 게 편합니다.

따라서 이 이벤트에 로그 처리를 하거나, 중요 데이터를 저장하는 것과 같은 중요한 기능을 구현할 때는 신중하게 구현해야 합니다.

사용방법은 다음과 같습니다.

return 으로 반환하는 문자열 내용은 무시되며, return 되는 값은 아무거나(빈 문자열 포함) 있기만 하면 됩니다.

addEventListener 메서드로는 알림창을 표시하는 이벤트를 생성할 수 없습니다. 반드시 다음처럼 onbeforeunload 이벤트 핸들러에 함수를 지정해야 합니다.

window.onbeforeunload = function () {
	return ''; 
}
크롬과 엣지 브라우저 화면 갱신과 페이지 나감 확인 알림 창
크롬과 엣지 브라우저 화면 갱신과 페이지 나감 확인 알림 창
preventDefault(), 또는 addEventListener() 를 사용하는 방법은 구 버전 웹 브라우저들에서만 지원되던 기능으로 최신 버전의 웹 브라우저에서는 모두 지원되지 않습니다.

beforeunload 이벤트 핸들러 안에는 alert(), confirm(), prompt()와 같은 팝업 대화 상자를 표시하는 메서드를 사용할 수 없습니다.

HTMl 규약에서 사용할 수 없도록 선언되어 있으며, 웹 브라우저에서도 에러와 함께 차단됩니다.

구글 크롬 alert() 차단

앞의 사용방법 처럼 return 문자열로 팝업 대화 상자에 표시할 메시지를 넣는 방식으로만 표시를 할 수 있습니다.

파이어폭스는 화면 갱신과 페이지를 나가는 것을 구분을 하지 못하면 페이지를 나가는 것으로만 처리됩니다.

파이어폭스 페이지 나감 알림 창

이벤트 중에는 beforeunload 와 유사한 unload 이벤트도 있습니다.

이름에서 알 수 있듯이 unload 바로 앞에 발생하는 이벤트가 beforeunload 이벤트입니다.

두 이벤트는 페이지가 언로드, 그러니까 페이지가 닫히는 시점(페이지를 벗어나거나 웹 브라우저 창을 닫는 경우)에 발생하고 거의 유사합니다.

단, beforeunload 이벤트 핸들러에서는 알림 창을 표시할 수 있지만, unload 이벤트 핸들러에서는 알림 창을 표시할 수 없습니다. 반드시 beforeunload 이벤트 핸들러로 호출해야 합니다.

beforeunload 비동기 호출 처리

beforeunload 이벤트 핸들러에서 특정 작업을 실행할 경우 해당 작업이 윈도우가 닫힌 뒤에도 실행될 수 있도록 해야 할 필요가 있습니다. 이런 경우를 위해 sendBeacon()과 같은 메서드를 이용해 윈도우가 닫힌 후에도 실행 완료를 보장할 수 있도록 하거나, 비동기 Fetch API에 keepalive와 같은 속성을 사용해서 비동기 호출이 완료될 수 있도록 할 수 있습니다.

웹 페이지가 닫히면 해당 시점에 요청된 네트워크 요청은 모두 취소되지만, 다음과 같이 Fetch API에 keepalive 속성을 추가하면, 해당 네트워크 요청이 취소되지 않고 웹 페이지가 닫힌 후에도 실행이 완료됩니다.(단, 전송할 수 있는 최대 데이터는 64Kb 이하로 제한됩니다.)

window.onbeforeunload = function() {
    fetch('/logger', {
        method: 'POST',
        body: new URLSearchParams({agent: 'agent-info', logdata: 'data'}),
        keepalive: true
    });
};

beforeunload 이벤트 핸들러 안에서 비동기 호출을 할 때는 몇가지 주의를 해야 합니다.

64Kb 데이터를 초과할 수 없습니다.

sendBeacon() 으로 비동기 데이터를 전송할 때, 데이터 타입에 제한이 있습니다.(text/plain, multipart/form-data, application.x-www-form-urlencoded)

beforeunload 이벤트 핸들러에 사용할 경우 가능하면 Fetch API 를 사용하는 것을 추천합니다.