이벤트 처리에서 옵저버와 이벤트 핸들러의 차이를 딥다이브 해보자!
개요

최근 옵저버와 이벤트 핸들러의 차이에 대해서 크게 신경쓰지 않다가, 최근에 크게 배우게 되는 일이 있었습니다.
다만, 모호한 부분이 있었어서 이 참에 다시금 정리하고자 글을 작성하게 되었습니다.
들어가기 전에..
한번쯤 떠올려보면 어떨까합니다. 이벤트 핸들러는 많이 사용해보셨을 것으로 예상되는데요.
그렇다면, 옵저버는 언제 사용해보셨나요?
- 무한 스크롤을 구현할 때 쓰는 InterSection Observer?
- 화면의 사이즈 조절을 감지할 때 쓰는 Resize Observer?
그렇다면, 여러분들은 이런 옵저버들을 왜 쓰셨나요?
Event Handler를 사용했을 때와 달리 어떤 장점이 있으셨나요?
한번쯤 떠올리고 다이브해봅시다!
옵저버(Observer)란 무엇인가?
여러분 옵저버란 무엇일까요?
혹시 어디서 들어보시진 않으셨나요?

스타크래프트에서 들어보셨다면.. 얼추 비슷하게 다가가셨습니다 ㅎㅎ.
옵저버는 말 그대로 "관찰자(Observer)"입니다.
정확히는 "관찰자 패턴(Observer Pattern)"에 기반한 메커니즘이지요.
그러면 여기서 무엇을 관찰할까요?
정답은 특정 대상의 상태 변화를 관찰합니다.
특정 대상의 상태 변화를 지속적으로 관찰하고, 변화가 감지되면 미리 등록된 콜백 함수를 실행하는 방식으로 동작하는게 옵저버입니다.
옵저버의 핵심 특징은 비동기적이고 지속적인 관찰입니다.
한 번 등록하면 조건이 충족될 때마다 자동으로 콜백이 실행되며, 개발자가 직접 상태를 확인할 필요가 없죠.
마치 보안 카메라가 움직임을 감지하면 자동으로 멈추는 것과 비슷합니다.
한번 IntersectionObserver를 예로 들어볼까요?
위 코드를 많이들 사용하셨을거라고 생각되어요. 특정 요소가 화면 상에 감지되면, 콜백을 실행시키는 코드입니다.
여기서 다음 부분이 보이시나요?
옵저버에게 어떤 것을 관찰하라고 시키는 겁니다. 여기서는 선택된 요소의 상태 변화를 감지하는 거라고 볼 수 잇겠네요.
IntersectionObserver는 DOM 요소가 뷰포트나 다른 요소와 교차하는 상황을 관찰합니다.
스크롤을 하거나, 요소의 위치가 변경될 때마다 자동으로 교차 상태를 확인하고, 조건에 맞으면 콜백을 실행하는 방식이죠.
이해가 안되어도 괜찮습니다. 이런게 있다 정도만 봐둡시다 ㅎㅎ.
이벤트 핸들러(Event Handler)란 무엇인가?
이벤트 핸들러는 이벤트 기반 프로그래밍의 핵심 요소입니다.
사용자의 클릭, 키보드 입력, 마우스 움직임 등 특정 이벤트가 발생했을 때 즉시 반응하여 콜백 함수를 실행합니다.
여기서의 핵심은 "즉시" 입니다. 이에 주목해주세요.
이벤트 핸들러의 특징은 즉각적이고 반응적인 실행입니다.
이벤트가 발생하는 순간 바로 콜백이 실행되며, 이벤트의 세부 정보(어떤 키를 눌렀는지, 어디를 클릭했는지 등)를 콜백 함수에 전달합니다.
이벤트 핸들러에 대해서는 잘 알 것 같아서 간단히만 언급하고 넘어가겠습니다 ㅎㅎ.
이벤트 핸들러와 옵저버의 차이
옵저버 vs 이벤트 핸들러 콜백 실행 방식 비교
| 구분 | 옵저버 (Observer) | 이벤트 핸들러 (Event Handler) |
|---|---|---|
| 실행 타이밍 | 브라우저 최적화 주기에 따라 실행 렌더링 프레임과 동기화 | 이벤트 발생 즉시 실행 사용자 액션과 직접 연결 |
| 실행 빈도 | 브라우저가 조절 (throttling 내장) 중복 호출 자동 최적화 | 이벤트 발생 횟수와 1:1 대응 빠른 연속 이벤트 시 과도한 호출 가능 |
| 콜백 큐 처리 | Intersection Observer Task Queue 낮은 우선순위로 처리 | Event Loop의 Task Queue 높은 우선순위로 즉시 처리 |
| 메인 스레드 블로킹 | 논블로킹 방식 메인 스레드 성능에 미치는 영향 최소 | 블로킹 가능성 복잡한 콜백 시 UI 응답성 저하 |
| 배치 처리 | 여러 변화를 배치로 묶어서 처리 entries 배열로 전달 | 개별 이벤트마다 별도 처리 각 이벤트는 독립적 |
| 브라우저 최적화 | 브라우저 엔진 수준에서 최적화 네이티브 구현의 성능 이점 | JavaScript 엔진 수준에서 처리 개발자가 직접 최적화 필요 |
| 리소스 사용량 | 낮은 CPU 사용률 GPU 가속 활용 가능 | 높은 CPU 사용률 특히 고빈도 이벤트에서 부담 |
| 예측 가능성 | 실행 시점 예측 어려움 브라우저 내부 스케줄링에 의존 | 실행 시점 예측 가능 이벤트 발생과 동시에 실행 |
| 디버깅 용이성 | 비동기적 특성으로 디버깅 복잡 콜백 실행 시점 추적 어려움 | 동기적 실행으로 디버깅 용이 이벤트-콜백 관계 명확 |
| 메모리 관리 | WeakRef 패턴 사용 자동 가비지 컬렉션 지원 | 명시적 메모리 관리 필요 리스너 해제 직접 처리 |
| 에러 처리 | 에러 발생 시 전체 관찰 중단 없음 개별 entry 단위로 에러 격리 | 에러 발생 시 해당 이벤트만 영향 다른 이벤트 처리에 영향 없음 |
| 크로스 브라우저 동작 | 표준 스펙 준수 브라우저별 최적화 차이 존재 | 오래된 표준으로 일관성 높음 브라우저별 차이 최소 |
간단하게 요약해보면 위와 같습니다.
감이 잡히시나요? 아직 모호할 것 같아서, 아래 성능 특성 비교를 통해 더 자세히 알아보겠습니다.
성능 특성 비교
조금 더 쉽게 보기 위해서 코드로 살펴볼까요?
어때요? 감이 좀 오시나요? 안오셨다고 해도 괜찮습니다 ㅎㅎ.
이제부터 본격적으로 하나씩 탐구해봅시다.
이벤트 핸들러 딥다이브
우선 이벤트 핸들러부터 살펴봅시다.
이벤트 핸들러의 본질적 특성
이벤트 핸들러를 이해하기 위해서는 먼저 이벤트 기반 프로그래밍의 철학을 파악해야 합니다.
이는 무언가가 일어나면 즉시 반응한다는 반응형 프로그래밍의 핵심 개념입니다.
마치 문지기가 문을 두드리면 즉시 문을 열어주는 것처럼, 이벤트 핸들러는 특정 신호(이벤트)를 받으면 미리 정해진 행동(콜백)을 즉시 수행합니다.
이때, "즉시"이라는 개념이 매우 중요합니다. 사용자가 버튼을 클릭하는 순간, 브라우저는 그 클릭을 감지하고 등록된 이벤트 핸들러를 찾아서 바로 실행합니다.
이 과정에서 지연이나 최적화를 위한 대기 시간은 없습니다.
이벤트 루프와의 관계
이벤트 핸들러의 실행 방식을 이해하기 위해서는, JavaScript의 이벤트 루프(Event Loop)를 이해해야 합니다.
이는 단일 스레드인 JavaScript가 비동기 작업을 어떻게 처리하는지를 보여주는 핵심 메커니즘입니다.
사용자가 클릭을 하면, 브라우저는 즉시 그 이벤트를 태스크 큐(Task Queue)에 넣습니다.
이벤트 루프는 현재 실행 중인 코드가 끝나면 즉시 태스크 큐에서 이벤트를 꺼내서 해당 핸들러를 실행합니다.
이 과정에서 우선순위가 높기 때문에, 다른 작업들보다 먼저 처리됩니다.
높은 실행 빈도의 문제점
이벤트 핸들러의 "즉시 실행" 특성은 때로는 성능 문제를 일으킵니다.
특히 고빈도 이벤트에서 이 문제가 두드러집니다.
스크롤이나 마우스 움직임 같은 이벤트는 초당 수십 번에서 수백 번까지 발생할 수 있는데, 매번 콜백이 실행되면 브라우저가 버거워할 수 있습니다.
이 문제를 해결하기 위해 개발자들은 쓰로틀링(Throttling)이나 디바운싱(Debouncing) 같은 기법을 사용합니다.
하지만 이는 이벤트 핸들러 자체의 한계를 보여주는 것이기도 합니다.
동기적 실행의 장단점
이벤트 핸들러는 동기적으로 실행됩니다. 이는 이벤트가 발생하면 다른 모든 JavaScript 코드의 실행을 잠시 멈추고 핸들러를 먼저 처리한다는 의미입니다.
이런 특성은 양날의 검과 같습니다.
장점으로는 예측 가능성이 있습니다. 사용자가 버튼을 클릭하면 정확히 그 순간에 핸들러가 실행되므로, 사용자 인터페이스의 반응성이 좋아집니다.
또한 디버깅할 때도 이벤트 발생과 핸들러 실행 사이의 인과 관계가 명확하게 보입니다.
하지만 단점도 있습니다. 핸들러 안에서 오래 걸리는 작업을 수행하면, 전체 페이지가 멈춘 것처럼 보일 수 있습니다. 이는 사용자 경험을 크게 해치는 요소입니다.
이벤트 핸들러의 이런 특성들을 이해하면, 왜 특정 상황에서는 옵저버가 더 나은 선택인지 알 수 있게 됩니다. 옵저버는 이런 문제들을 브라우저 수준에서 해결하기 위해 설계된 다른 접근 방법이기도 합니다.
동기적 실행이란?
좀 더 자세히 들어가기 전에 "동기적 실행"이 무엇인지 명확히 이해해봅시다.
보통 동기적 실행이라고 하면, 코드가 한 줄 씩 순서대로 실행되는 것을 생각합니다. 그러나, 실제로는 단순히 "순서대로 실행된다."는 의미가 아닙니다.
더 명확히 말하면, "한 번에 하나의 작업만 수행하며, 현재 작업이 완전히 끝날 때까지 다른 모든 작업이 기다린다"는 의미입니다.
한번 생각해봅시다. 여러분이 책을 읽고 있는데, 누군가 말을 걸었다고 가정해봐요. 여러분은 책 읽기를 완전히 멈추고 그 사람의 말에 집중한 다음, 대화가 끝나면 다시 책을 읽기 시작할 거에요.
이것이 바로 동기적 실행의 방식입니다. 두 가지 일을 동시에 하지 않고, 하나씩 완전히 처리하는 방식. 인 것이지요.
이 예시에서 사용자가 버튼을 클릭하면, 클릭 이벤트 핸들러가 완전히 끝날 때까지 다른 모든 JavaScript 작업들이 멈춥니다.
다른 클릭, 타이머 콜백, 네트워크 응답 처리 등 모든 것이 기다려야 하는 것이죠.
예측 가능성의 진정한 의미
동기적 실행의 가장 큰 장점은 예측 가능성입니다. 하지만 이것이 단순히 "실행 순서를 예측할 수 있다"는 의미는 아닙니다.
더 중요한 것은 상태의 일관성을 보장한다는 점이에요.
예를 들어, 사용자가 "저장" 버튼을 클릭했다고 생각해봐요. 이 순간에 여러 가지 작업이 필요할 수 있어요.
폼 데이터를 검증하고, UI를 업데이트하고, 서버에 요청을 보내야 할 수도 있습니다. 동기적 실행에서는 이런 작업들이 원자적으로(atomically) 처리됩니다.
만약 이 과정이 중간에 끊어질 수 있다면 어떻게 될까요?
사용자가 빠르게 여러 번 클릭했을 때, 폼 검증은 완료됐는데 UI 업데이트는 되지 않은 상태가 발생할 수 있습니다. 이런 중간 상태는 버그의 원인이 되기 쉽습니다.
즉각적 피드백의 심리적 효과
동기적 실행이 제공하는 즉각적 피드백은 단순히 기술적인 이점을 넘어서 사용자 경험의 핵심입니다.
인간의 뇌는 행동과 결과 사이의 지연을 매우 민감하게 감지합니다.
연구에 따르면, 100밀리초 이하의 응답 시간에서는 사용자가 "즉각적"이라고 느끼고, 1초를 넘어가면 "느리다"고 인식합니다.
이런 즉각적 피드백은 사용자가 인터페이스를 "살아있는" 것으로 느끼게 만듭니다.
버튼을 누르면 즉시 반응하고, 마우스를 올리면 바로 하이라이트되는 것들이 모두 동기적 실행의 이점입니다.
디버깅에서의 명확한 인과관계
개발자 입장에서 동기적 실행의 가장 큰 장점 중 하나는 디버깅의 용이성입니다.
이벤트가 발생하고 핸들러가 실행되는 과정이 명확하고 예측 가능하기 때문에, 문제가 발생했을 때 원인을 찾기가 상대적으로 쉽습니다.
이와 대조적으로, 비동기적으로 처리되는 작업들은 실행 순서가 예측하기 어렵고, 디버깅할 때 훨씬 복잡한 상황을 만들어냅니다.
메인 스레드 블로킹의 실제 영향
하지만 동기적 실행의 단점도 명확합니다. 가장 심각한 문제는 메인 스레드 블로킹입니다. 이를 구체적으로 이해해보겠습니다.
JavaScript는 UI 스레드와 같은 스레드에서 실행됩니다. 즉, JavaScript 코드가 실행되는 동안에는 화면 렌더링, 사용자 입력 처리, 애니메이션 등 모든 UI 관련 작업이 멈춥니다. 이것이 바로 "블로킹"의 의미입니다.
이런 상황에서 사용자는 "웹사이트가 느리다" 또는 "버그가 있다"고 느끼게 됩니다. 특히 모바일 기기에서는 이런 문제가 더욱 두드러집니다.
성능 문제의 누적 효과
메인 스레드 블로킹은 단순히 해당 순간만의 문제가 아닙니다.
누적 효과가 있습니다. 브라우저는 초당 60프레임을 목표로 하는데, 이는 16.67밀리초마다 화면을 다시 그려야 한다는 의미입니다.
만약 이벤트 핸들러가 이 시간을 넘어서 실행된다면, 프레임 드랍이 발생합니다.
이런 문제는 특히 상호작용이 많은 웹 애플리케이션에서 심각한 사용자 경험 저하를 일으킵니다. 게임, 그래픽 에디터, 실시간 차트 등에서는 이런 성능 문제가 치명적일 수 있습니다.
해결 전략들
동기적 실행의 단점을 극복하기 위해 개발자들은 여러 전략을 사용합니다. 가장 기본적인 것은 작업 분할입니다.
이런 방식으로 동기적 실행의 장점은 유지하면서 단점을 최소화할 수 있습니다. 하지만 이것도 근본적인 해결책은 아닙니다.
이런 한계 때문에 IntersectionObserver 같은 새로운 API들이 등장한 것입니다.
옵저버 패턴의 딥다이브
이제 이벤트 핸들러의 동기적 실행 방식을 깊이 이해했으니, 옵저버의 세계로 들어가 보겠습니다.
앞에서 이미 옵저버 패턴이 무엇인가에 대해서 보았지만, 좀 더 깊게 들어가는 세션이라고 봐주시면 될 것 같아요.
옵저버를 이해하는 것은 마치 전혀 다른 사고 방식을 배우는 것과 같습니다. 이벤트 핸들러가 "무언가 일어나면 즉시 반응하라"는 명령형 접근이라면, 옵저버는 "무언가를 지켜보다가 변화가 있으면 알려달라"는 선언형 접근입니다.
옵저버를 이해하기 위해서는 먼저 그 철학적 기초를 파악해야 합니다.
이벤트 핸들러에서는 개발자가 능동적으로 "언제 무엇을 확인할지"를 결정합니다.
예를 들어 스크롤 이벤트를 듣고, 그 순간마다 요소의 위치를 확인하는 식입니다.
하지만 옵저버에서는 "무엇을 관찰할지"만 정의하고, "언제 확인할지"는 브라우저에게 맡깁니다.
이는 마치 경비원과 CCTV의 차이와 같습니다.
경비원(이벤트 핸들러)은 순찰을 돌면서 직접 상황을 확인해야 하지만, CCTV(옵저버)는 설치만 해두면 자동으로 감시하다가 문제가 생기면 알려줍니다.
CCTV가 더 효율적인 이유는 24시간 지속적으로 관찰할 수 있고, 여러 곳을 동시에 감시할 수 있으며, 실제로 문제가 생겼을 때만 알림을 보내기 때문입니다.
브라우저 최적화 주기와의 동기화
옵저버의 가장 중요한 특징 중 하나는 브라우저의 렌더링 주기와 동기화된다는 점입니다.
이는 매우 중요한 개념인데, 이를 이해하려면 브라우저가 어떻게 화면을 그리는지 알아야 합니다.
브라우저는 일반적으로 초당 60프레임으로 화면을 업데이트합니다.
이는 약 16.67밀리초마다 다음과 같은 과정을 거친다는 의미입니다.
먼저 JavaScript 실행, 스타일 계산, 레이아웃 계산, 페인트, 컴포지트 순서로 진행됩니다. IntersectionObserver의 콜백은 이 렌더링 파이프라인의 특정 시점에서 실행됩니다.
이런 동기화 덕분에 옵저버는 정확한 정보를 제공할 수 있습니다.
브라우저가 이미 모든 계산을 마친 후에 콜백을 실행하기 때문에, 개발자가 받는 정보는 신뢰할 수 있는 최신 상태입니다.
배치 처리의 효율성
옵저버가 이벤트 핸들러보다 효율적인 또 다른 이유는 배치 처리 방식입니다.
여러 요소의 상태가 동시에 변경되어도, 옵저버는 이를 하나의 콜백 호출로 묶어서 처리합니다. 이는 성능상 큰 이점을 제공합니다.
생각해보세요. 페이지에 100개의 이미지가 있고, 사용자가 빠르게 스크롤한다면 어떻게 될까요?
이벤트 핸들러 방식에서는 스크롤 이벤트가 발생할 때마다 100개 이미지의 위치를 모두 확인해야 합니다.
하지만 옵저버 방식에서는 브라우저가 "이번 프레임에서 변화가 있었던 이미지들"만 모아서 한 번에 알려줍니다.
이 예제에서 주목할 점은 사용자가 아무리 빠르게 스크롤해도, 각 렌더링 프레임마다 최대 한 번의 콜백만 실행된다는 것입니다.
만약 한 프레임에서 10개의 이미지가 동시에 화면에 나타났다면, 10번의 개별 호출 대신 10개 요소가 담긴 배열과 함께 한 번의 콜백이 실행됩니다.
논블로킹 실행의 의미
옵저버의 또 다른 핵심 특징은 논블로킹 실행입니다.
이는 단순히 "메인 스레드를 블록하지 않는다"는 의미를 넘어서, 더 근본적인 실행 철학의 차이를 보여줍니다.
이벤트 핸들러에서는 핸들러 함수가 실행되는 동안 다른 모든 작업이 기다려야 합니다.
하지만 옵저버에서는 콜백 함수 자체는 여전히 메인 스레드에서 실행되지만, 관찰 작업 자체는 브라우저의 다른 시스템에서 처리됩니다.
이는 관찰 대상이 아무리 많아도 JavaScript 실행에는 거의 영향을 주지 않는다는 의미입니다.
브라우저 엔진 수준의 최적화
옵저버가 강력한 이유 중 하나는 브라우저 엔진 수준에서 최적화되어 있다는 점입니다.
이는 JavaScript로는 구현하기 어려운 수준의 최적화를 제공합니다.
예를 들어, 브라우저는 GPU를 활용하여 변환 행렬 계산을 가속화할 수 있습니다.
또한 브라우저는 실제로 화면에 보이지 않는 요소들에 대해서는 불필요한 계산을 생략할 수 있습니다.
이런 최적화들은 JavaScript 수준에서는 접근할 수 없는 브라우저 내부의 정보를 활용합니다.
메모리 관리의 자동화
옵저버는 메모리 관리 측면에서도 이벤트 핸들러와 다른 접근을 합니다.
옵저버는 WeakRef 패턴을 내부적으로 사용하여, 관찰 대상 요소가 DOM에서 제거되면 자동으로 해당 관찰을 정리합니다.
이는 메모리 누수를 방지하는 데 큰 도움이 됩니다.
지금까지 옵저버의 기본적인 특성들을 살펴봤습니다.
이제 이벤트 핸들러와의 차이점이 더 명확하게 보이시나요?
브라우저 렌더링 파이프라인과 옵저버
브라우저 렌더링 패스에서 옵저버가 언제 실행되는 지를 한번 살펴봅시다.
렌더링 패스에서의 실행 시점을 이해하는 건, 오케스트라에서 각 악기가 언제 연주되는지를 아는 것과 같아요.
각 옵저버는 브라우저의 렌더링 파이프라인에서 서로 다른 시점에서 실행되며, 이 시점을 이해하면 왜 특정 옵저버가 특정 작업에 적합한 지 알 수 있게 됩니다.
브라우저 렌더링 파이프라인의 이해
브라우저가 한 프레임을 렌더링하는 과정을 차근차근 살펴볼게요.
이 과정을 이해해야 각 옵저버가 어느 단계에서 실행되는지 명확하게 파악할 수 있어요.
브라우저의 렌더링 파이프라인은 일반적으로 다음과 같은 순서로 실행됩니다.
먼저 JavaScript 실행 단계에서 사용자 코드와 이벤트 핸들러가 실행되빈다.
다음으로 스타일 계산 단게에서 CSS 규칙을 적용하여 각 요소의 최종 스타일을 결정합니다.
그 후 레이아웃 단계에서 각 요소의 정확한 위치와 크기를 계산해요.
페인트 단계에서는 실제 픽셀 데이터를 생성하고, 마지막으로 컴포지트 단게에서 여러 레이러를 합성하여 최종 화면을 만듭니다.
각 옵저버는 이 파이프라인의 서로 다른 지점에서 실행되며, 이는 그들이 접근할 수 있는 정보와 성능 특성을 결정
합니다.
생각해봅시다. 레이아웃이 계산되기 전에 실행되는 옵저버는 정확한 위치 정보를 얻을 수 없지만, 레이아웃 후에 실행되는 옵저버는 정확한 정보를 제공할 수 있습니다.
IntersectionObserver: 레이아웃 후 실행
IntersectionObserver는 가장 널리 알려진 옵저버로, 레이아웃 계산이 완료된 후에 실행됩니다.
이는 매우 중요한 특성인데, 요소의 정확한 위치와 크기 정보가 필요하기 때문입니다.
IntersectionObserver가 레이아웃 후에 실행된다는 것은 성능상 큰 의미가 있습니다.
만약 JavaScript에서 직접 getBoundingClientRect()를 호출한다면, 브라우저는 즉시 레이아웃을 강제로 계산해야 합니다.
하지만 IntersectionObserver는 브라우저가 자연스럽게 레이아웃을 계산한 후에 실행되므로, 불필요한 레이아웃 재계산을 방지합니다.
ResizeObserver: 레이아웃 직후 실행
ResizeObserver는 요소의 크기 변화를 감지하는 옵저버입니다.
이는 IntersectionObserver와 비슷한 시점에 실행되지만, 약간 더 이른 시점에서 실행될 수 있습니다.
ResizeObserver는 레이아웃 계산 단계와 매우 밀접하게 연결되어 있기 때문입니다.
ResizeObserver의 흥미로운 특성 중 하나는 무한 루프를 방지하는 메커니즘이 있다는 것입니다.
만약 ResizeObserver 콜백 내에서 관찰 대상의 크기를 변경한다면, 브라우저는 이를 감지하고 적절히 처리합니다.
이는 복잡한 반응형 레이아웃을 안전하게 구현할 수 있게 해줍니다.
MutationObserver: DOM 변경 즉시 실행
MutationObserver는 다른 옵저버들과는 실행 시점이 완전히 다릅니다.
이는 DOM 구조의 변화를 감지하므로, 렌더링 파이프라인의 가장 초기 단계에서 실행됩니다.
정확히는 DOM 변경이 일어난 직후, 하지만 스타일 계산이나 레이아웃 계산이 시작되기 전에 실행됩니다.
MutationObserver가 초기 단계에서 실행된다는 것은 중요한 의미가 있습니다.
이는 DOM 구조 변경에 대한 즉각적인 반응을 가능하게 하지만, 동시에 아직 최종적인 레이아웃 정보는 사용할 수 없다는 의미이기도 합니다.
따라서 MutationObserver는 주로 DOM 구조 자체를 관리하는 용도로 사용됩니다.
PerformanceObserver: 성능 측정 전문
PerformanceObserver는 브라우저의 성능 메트릭을 관찰하는 특별한 옵저버입니다.
이는 렌더링 파이프라인의 여러 지점에서 수집된 성능 데이터를 제공하므로, 다른 옵저버들과는 완전히 다른 실행 패턴을 가집니다.
PerformanceObserver는 웹 애플리케이션의 성능을 실시간으로 모니터링하는 데 매우 유용합니다.
특히 Core Web Vitals 같은 사용자 경험 메트릭을 측정할 때 필수적인 도구입니다.
옵저버들의 실행 순서와 상호작용
여러 옵저버가 동시에 활성화되어 있을 때, 브라우저는 어떤 순서로 이들을 실행할까요?
이는 각 옵저버가 렌더링 파이프라인의 어느 지점에서 실행되는지와 직접적으로 관련이 있습니다.
이 예제를 실행하면, 옵저버들이 브라우저의 렌더링 파이프라인 순서에 따라 실행되는 것을 확인할 수 있습니다.
이런 실행 순서를 이해하면, 복잡한 상호작용이 있는 애플리케이션에서도 예측 가능한 동작을 구현할 수 있습니다.
정리
글이 꽤나 길었네요.
이번 주제를 통해서, 이벤트 핸들러와 옵저버의 차이, 그리고, 브라우저 렌더링 파이프라인에서 옵저버가 어떤 타이밍에 실행되는지 등을 자세히 알 수 있었길 바랍니다.
궁금한 점은 댓글로 남겨주시면 확인되는대로 빠르게 답장 남길게요!
긴 글 읽어주셔서 감사합니다. 🙇