SPA가 대중적으로 많이 퍼지면서 여러 브라우저를 오가며 복잡한 작업을 하는 경우는 적어진 것 같다.
하지만, 여전히 다양한 이유로 여러 탭을 사용하여 오가는 웹 앱이 필요하고, 그 때 탭간의 데이터 통신을 위해서 사용할 수 있는 API들이 있다.
그 API들 중에서 이번엔 postMessage와 BroadcastChannel을 사용하는 방법에 대해서 간단하게 알아보았다.
일단 window. postMessage를 사용해보자.
postMessage를 통해서 새로 띄워진 창에 메세지를 전달할 수 있다.
일단, window.open 메서드로 새로운 창을 띄운다.
const newWindow = window.open("https://www.naver.com");
그럼 새로운 네이버 탭이 열린다.
이 탭의 콘솔창을 열어 이벤트를 연결해두자.
function receiveMessage(event) {
if (event.origin !== "https://www.naver.com")
return;
console.log(event)
}
window.addEventListener("message", receiveMessage, false);
+ event.origin을 검사하는 건 보안적으로 좋은 습관이지만, event.source를 같이 확인하는 게 더 안전하다.
같은 origin이라도, 악성 코드가 메시지를 보낼 가능성이 있기 때문이다 👻
function receiveMessage(event) {
if (event.origin !== "https://www.naver.com") return;
if (event.source !== trustedWindow) return; // 신뢰할 수 있는 창인지 확인
console.log(event);
}
이제 이벤트를 직접 보내면, 새로 열린 탭에서 데이터를 전달받을 수 있다.
newWindow.postMessage("GOOOOOOOOOOOOOOOOOOD", "https://www.naver.com")
+ postMessage를 사용할 때, 새 창이 완전히 로드되지 않은 상태에서 메시지를 보내면 무시될 수 있다.
때문에, onload를 사용해 시점을 잡아주는 것이 좋다.
const newWindow = window.open("https://www.naver.com");
newWindow.onload = () => {
newWindow.postMessage("GOOOOOOOOOOOOOOOOOOD", "https://www.naver.com");
};
새로 열렸던 창의 콘솔창을 확인해보면,
메세지가 전달된 것을 확인할 수 있다.
다만, 새로 열린 창을 사용해야 하는 불편함이 있다.
대신, 다른 origin 도메인과도 통신할 수 있다.
이번에는 BroadcastChannel을 사용해보자.
BroadcastChannel API는 same-origin이고, 동일한 출처로부터 온것을 보장하기에 위와 같이 event.origin을 검사할 필요가 없다.
직접 사용해보면, 일단 다음과 네이버 두 탭을 띄우자.
그리고 두 탭에 각각 채널을 생성해준다. (동일한 채널이름)
const channel = new BroadcastChannel('test');
그리고 다음 탭에 onmessage 이벤트를 설정한다.
channel.onmessage = function(e) {
console.log('Received', e.data);
};
그리고 네이버 탭에서 메세지를 보내면,
channel.postMessage('This is a test message.');
반응이 없을 것이다. 😅
same-origin이 아니기에 데이터를 받을 수 없었다.
+ BroadcastChannel을 사용할 때, 사용이 끝나면 반드시 close()를 호출해야 한다. 안 그러면 메모리 누수가 발생할 수 있다.
const channel = new BroadcastChannel("test");
channel.onmessage = (e) => {
console.log("Received", e.data);
};
// 사용이 끝났다면 반드시 닫기!
channel.close();
다시 네이버 탭을 띄우고, 채널을 설정한 뒤 onmessage 이벤트를 설정하면 정상 작동함을 확인할 수 있다.
요약하자면, 다음과 같다.
// BroadcastChannel 인스턴스 생성
const channel = new BroadcastChannel('test');
// 메시지 수신 설정
channel.onmessage = function(e) {
console.log('Received', e.data);
};
// 메시지 보내기
channel.postMessage('This is a test message.');
origin이 같은 모든 탭에 데이터를 보내기에, 각 탭에서 id를 설정해서 원하는 탭에서만 데이터를 받을 수 있도록 설정할 수도 있다.
const channel = new BroadcastChannel("test");
const myTabId = Math.random().toString(36).substr(2, 9); // 각 탭의 고유 ID 생성
channel.onmessage = (e) => {
if (e.data.targetId && e.data.targetId !== myTabId) return; // 특정 탭이 아니면 무시
console.log("Received", e.data.message);
};
// 특정 탭으로 메시지 보내기
function sendMessageToTab(targetId, message) {
channel.postMessage({ targetId, message });
}
(id 설정 후 해당 id를 포함해서 데이터가 올 때에만 데이터 수신하도록 onmessage를 설정할 수 있다)
🍇 참고 자료
https://developer.mozilla.org/ko/docs/Web/API/Window/postMessage
Window.postMessage() - Web API | MDN
window.postMessage() 메소드는 Window 오브젝트 사이에서 안전하게 cross-origin 통신을 할 수 있게 합니다. 예시로, 페이지와 생성된 팝업 간의 통신이나, 페이지와 페이지 안의 iframe 간의 통신에 사용할
developer.mozilla.org
https://developer.chrome.com/blog/broadcastchannel?hl=ko
BroadcastChannel API - 웹용 메시지 버스 | Blog | Chrome for Developers
BroadcastChannel API는 창, 탭, iframe 또는 작업자 간의 간단한 Pub/Sub에 사용할 수 있습니다.
developer.chrome.com
+ 2025.03.20 내용 보완
'웹 개발' 카테고리의 다른 글
resize Event와 ResizeObserver 비교해보기 🙌 (0) | 2024.10.18 |
---|---|
requestIdleCallback 알아보기 (브라우저가 idle할 때, 콜백함수를 대기열에 👍) (0) | 2024.09.05 |
commonJS, ESM 둘 다 지원하는 package.json 설정법 (feat. rollup) (0) | 2024.08.18 |
프론트엔드 개발 생태계에서 Rust 개발 툴들 (0) | 2024.07.02 |
Biome.js 사용 후기 (prettier + eslint) (0) | 2024.06.24 |