vue.js의 내부 구현을 알아봅니다.
원문 : https://medium.com/js-imaginea/the-vue-js-internals-7b76f76813e3
저는 github의 소스를 살펴보고 vue 내부에서 무슨 일이 일어나는지 이해하기 위해 여러 차례 디버깅을 했습니다.
이 게시물은 여기 4가지 질문에 대한 답변을 제공하려고 합니다.
- Vue.js 인스턴스를 생성하면 무슨 일이 일어날까요?
- 템플릿은 내부적으로 어떻게 처리되나요?
- 가상 DOM의 중요성은 무엇인가요?
- property가 변경될 때 템플릿 리렌더링은 어떻게 발생하나요?
컴포넌트는 브라우저에 표시하기 전에 다양한 단계를 통과해야 하는 템플릿을 포함합니다.
작은 템플릿을 예제로 사용하여 설명하겠습니다.
<div id="app">
<span v-if="dynamic">Dynamic text</span>
<span><p>Static text</p></span>
<button @click="toggleFlag">Toggle Dynamic</button>
</div>
컴파일 단계
파싱 단계
이 컴파일 단계는 특정 컴포넌트의 템플릿으로 전달된 마크업과 함께 수행됩니다.
이미지에서 볼 수 있듯이 파서는 먼저 템플릿을 HTML 파서로 파싱하고
차례로 AST(추상 구문 트리;Abstract syntax tree)로 변환합니다.
최적화 단계
정적 하위 트리를 감지하면 Vue가 이를 상수로 호이스트하여 Vue가 다시 렌더링할 때마다 새로운 노드를 생성하지 않도록 합니다.
이러한 노드는 가상 DOM의 패치 프로세스(patching process) 중에 완전히 건너뜁니다.
코드 생성(CodeGen) 단계
참고: 빌드 단계를 사용하는 경우 템플릿 컴파일이 미리 수행됩니다.
예를 들어 SFC(single file components)를 사용할 경우입니다.
반응형 컴포넌트의 Observer & Watcher
Observer
내부적으로 Vue는 데이터에 정의한 모든 속성을 살펴보고 Object.defineProperty를 사용하여
이를 getter/setter로 변환합니다.
주 : 요새는 프록시 쓰는걸로 압니다
var o = Object.create(null);
var bValue = 12;
Object.defineProperty(o, 'b', {
get() {
return bValue;
},
set(newValue) {
bValue = newValue;
/*
In our example when the value of dynamic data property change it's watcher will be notify
*/
}
});
o.b = 45 // notify the watcher
Watcher
패치 프로세스(The Patch proces)
이 프로세스는 모두 이전 VNode(가상 DOM 노드)와 새로운 VNode 에 관한 이야기 입니다.
즉, 이 둘을 서로 비교할 것입니다.
알고리즘은 다음과 같은 방식으로 동작합니다.
- 먼저 Old VNode가 있는지 여부를 확인하고 없으면 각 VNode에 대한 DOM 요소를 만듭니다.
- 앱을 처음 구동하고 첫 번째 렌더링 프로세스가 시작된 경우, 이전 VNode가 없을 것입니다.
- 이전 VNode가 있는 경우 두 자식 비교 프로세스가 시작됩니다.
- 공통 노드는 DOM에 유지됩니다.
- 새 노드는 추가됩니다.
- 일치하지 않는 노드는 Virtual DOM에서 제거된 것이며, 실제 돔에서 제거됩니다.
모든 노드에 대해 동일한 프로세스가 재귀적으로 수행됩니다.
또한, 최적화 단계에서 논의한 정적 노드를 떠올려 봅시다.
정적 노드의 트리는 그대로 사용됩니다.
우리는 이런 종류의 트리에 대해 실제 DOM과 상호 작용할 필요가 없습니다.
라이프 사이클 훅
- The Creation
- The Mounting
- The Updating
- The Destruction.
- beforeCreation: 이벤트를 수집하기 전, 컴포넌트에 필요한 데이터. 즉, watcher / 의존성을 수집하는 프로세스를 진행 중입니다.
- created: Vue가 data와 watcher의 setup을 마쳤을 때의 상태입니다.
- beforeMount: 패치 프로세스 실행 전 상태입니다. VNode는 data와 watcher를 기반으로 생성됩니다.
- mount : 생성을 위한 패치 프로세스를 완료한 이후 상태를 나타냅니다.
- beforeUpdate: watcher는 VNode를 업데이트하고 데이터가 변경되면 패치 프로세스를 다시 시작합니다.
- update : 업데이트를 위한 패치 프로세스가 완료 된 상태입니다.
- beforeDestory : 컴포넌트를 제거하기 이전 상태입니다. 컴포넌트는 화면에 나타난 상태이며 기능 중입니다.
- destroyed : watcher를 제거하고, 해당 컴포넌트의 이벤트 리스너와 칠드런 컴포넌트들을 제거한 상태입니다.
결론
- 컴포넌트 단위로 렌더링 함수가 생성되며 이때 정적 렌더 함수를 호이스팅하여 업데이트 계산에서 제외한다
- 부모 컴포넌트의 리렌더링 반드시 자식 컴포넌트의 리렌더링을 유발하는 것은 아니며, reactivity 의존성에 따라 다르다.
- 컴파일 단계는 정적 템플릿의 최적화를 해준다
더보기 : https://vuejs.org/guide/extras/rendering-mechanism.html
Originally posted at blog.imaginea.com
'FrontEnd' 카테고리의 다른 글
RxJS와 반응형 프로그래밍 (0) | 2022.10.06 |
---|---|
디자인시스템 토큰 이름붙이기 [Naming Tokens in Design Systems] (0) | 2022.10.05 |
자바스크립트 참조에 관한 시각적 가이드 [aka 자바스크립트 포인터] (0) | 2022.10.03 |
[React hooks] 리액트 훅의 원리 : 단지 배열일 뿐 (0) | 2022.10.03 |
리덕스 이후의 삶(Life after Redux) : 리덕스 없이 리덕스 장점 누리기 (0) | 2022.10.03 |