본문으로 건너뛰기
yceffort
PostsSeriesTagsAbout🧪 Research
EN

Tweaks

theme
accent palette
film grain
minimal mode
BACK TO INDEX
◆ ESSAY
--min
--year
KOoriginal

mailMail icongithubtwitter
yceffort
•
© 2026
•
https://yceffort.kr
BACK TO INDEX
◆ ESSAY

브라우저 탭 사이에서 통신 하는 방법

avatar
yceffort
2020-11-06 · 3분
3min
2020year
KOoriginal
browserjavascript

한 사이트가 여러 탭에서 떠 있을 때, 탭 사이에서 통신이 필요한 경우가 있을까?

  • 한 탭에서 사이트의 테마를 변경해서 다른 탭에 있는 사이트에까지 변경이 필요한 경우
  • 애플리케이션의 상태를 탭 사이에 맞춰야 하는 경우
  • 가장 최근에 가져온 인증 정보를 브라우저 탭 간에 공유가 필요한 경우

이를 달성할 수 있는 방법이 무엇이 있을까?

Local Storage

놀랍게도 로컬 스토리지에도 event를 지원한다. 이 event를 활용해서 localStorage의 변화를 감지하는 방법이다.

React.useEffect(() => {
  function listener(event: StorageEvent) {
    if (event.storageArea !== localStorage) return
    if (event.key === LOGGINED) {
      setLoginTime(parseInt(event.newValue || '0', 10))
    }
  }
  window.addEventListener('storage', listener)

  return () => {
    window.removeEventListener('storage', listener)
  }
}, [])

https://codesandbox.io/s/tab-communications-1-localstorage-5ldjw

잘 작동하는 것 같지만 몇가지 문제가 존재한다.

  • 정확히는 탭 별로 이벤트가 발생하는게 아니고 storage의 event를 가져다 쓰는 꼼수라는 점
  • localStorage는 동기로 작동하기 때문에 메인 UI 스레드를 블로킹할 수도 있음.

Broadcast Channel API

BroadCast Channel API는 탭, 윈도우, 프레임, iframe 그리고 Web worker 간에 통신을 할 수 있게 해주는 API다.

이 방법을 쓰면, 브라우저 콘텍스트 간에 통신이 가능해진다.

const LOGGINED = "loggedIn";

const channel = new BroadcastChannel(LOGGINED);

export default function App() {
  const [loginTime, setLoginTime] = React.useState<number>(() =>
    parseInt(window.localStorage.getItem(LOGGINED) || "0", 10)
  );

  React.useEffect(() => {
    function listener(event: MessageEvent) {
      setLoginTime(event.data);
    }

    channel.addEventListener("message", listener);

    return () => {
      channel.removeEventListener("message", listener);
    };
  }, []);

  return (
    // jsx
  );
}

https://codesandbox.io/s/tab-communications-2-braodcast-channel-m50d6

코드가 어딘가 이상하다면 그냥 무시해주셈

다만 문제점은 Broadcast Channel Api는 너무 힙한 나머지 사파리와 IE에서 쓸 수 없다는 점다.

Service Worker

서비스 워커를 이용하는 방법도 있다.

window.navigator.serviceWorker.controller?.postMessage({
  [LOGGINED]: currentDateTime,
})

그리고 이 정보를 서비스워커에서 받으면 된다. 그러나 서비스 워커를 세팅하는 것은 쉽지 않고, 추가적으로 serviceWorker.js등을 만드는 등의 노력이 필요하다. 그리고 서비스 워커도 마찬가지로 IE에서 지원하지 않는다.

postMessage

가장 전통적이고도 널리 쓰이는 방식은 window.postmessasge다. 아마 대다수의 서비스들이 이 방식을 쓰고 있을 것이다.

targetWindow.postMessage(message, targetOrigin)
window.addEventListener(
  'message',
  (event) => {
    if (event.origin !== 'http://localhost:8080') return
    // Do something
  },
  false,
)

이 방법의 장점은 cross-origin을 지원한다는 것이다. 그러나 단점은 위 코드에서 알 수 있듯이 브라우저 탭의 레퍼런스를 가지고 있어야 한다. (targetWindow를 가지고 있는 것 같이) 그래서 이 방식은 window.open()이나 document.open()을 통해서 탭을 열었을 때만 사용 가능하다.

https://caniuse.com/mdn-api_window_postmessage

관련 글

  • #javascript#browser

    V8에서 관리되는 자바스크립트 변수

    V8 내부 코드를 자유롭게 읽을 수 있는 그날까지

    2022-04-21·10분
  • #javascript#nodejs#browser

    브라우저와 Nodejs의 이벤트 루프는 무엇이 다를까

    인생은 돌고 도는 이벤트 루프

    2021-08-10·16분
  • #web-performance#javascript#browser

    웹 페이지에서의 자바스크립트 메모리 사용량 벤치마킹

    분석할 때 마다 한숨이 나오는 그것

    2021-08-07·13분
  • #javascript#browser

    V8 엔진에 대해 가볍게 살펴보기

    맛만 볼게 아니고 직접 코드 까봐서 공부를 해봐야 되는데 😭

    2020-11-27·14분

새 글을 놓치고 싶지 않으시다면 RSS로 구독해 주세요.

RSS 구독 →

yceffort — 프론트엔드 엔지니어입니다. 발표·기술 자문·기고 문의는 이곳에서 받고 있습니다.

← Back to the blogIssue on GitHub →