Vue 3 의 VDOM 개선 에 대한 자세 한 설명
vue-next 는 virtual dom 의 patch 업데이트 에 대해 일련의 최적화 를 했 고 컴 파일 할 때 block 을 추가 하여 vdom 간 의 대비 횟수 를 줄 였 으 며,또한 hoisted 의 조작 은 메모리 비용 을 줄 였 다.본 고 는 자신 에 게 보 여주 고 지식 적 인 기록 을 하 며 잘못 이 있 으 면 아낌없이 가르쳐 주 십시오.
VDOM
VDOM 의 개념 은 쉽게 말 하면 js 대상 으로 실제 DOM 트 리 를 모 의 하 는 것 이다.MV**의 구조 로 인해 실제 DOM 트 리 는 데이터(Vue2.x 중의 data)의 변화 에 따라 달라 져 야 합 니 다.이런 변 화 는 다음 과 같은 몇 가지 측면 일 수 있 습 니 다.
Vue 2.x 의 방법
Vue 2.x 에서 데이터 가 바 뀌 면 모든 노드 에 패 치 와 diff 작업 을 해 야 합 니 다.다음 DOM 구조 와 같이:
<div>
<span class="header">I'm header</span>
<ul>
<li> li</li>
<li v-for="item in mutableItems" :key="item.key"> {{ item.desc }}</li>
</ul>
</div>
첫 번 째 mount 노드 에서 실제 DOM 을 생 성 합 니 다.그 다음 에 만약 에...
mutableItems.push({
key: 'asdf',
desc: 'a new li item'
})
예상 되 는 결 과 는 페이지 에 새로운 li 요소 가 나타 나 는 것 입 니 다.내용 은 a new li item 입 니 다.Vue 2.x 에 서 는 patch 를 통 해 ul 요소 에 대응 하 는 vnode 의 children 에 대해 diff 작업 을 합 니 다.구체 적 인 조작 은 여기 서 깊이 연구 하지 않 지만 이 조작 은 모든 li 에 대응 하 는 vnode 를 비교 해 야 합 니 다.모자라다
바로 2.x 버 전의 diff 작업 은 모든 요 소 를 옮 겨 다 녀 야 하기 때문에 이 예 에는 span 과 첫 번 째 li 요소 가 포함 되 어 있 습 니 다.그러나 이 두 요 소 는 정적 이 고 비교 할 필요 가 없습니다.데이터 가 아무리 변 하 더 라 도 정적 요 소 는 더 이상 변경 되 지 않 습 니 다.vue-next 는 컴 파일 할 때 이러한 조작 을 최적화 시 켰 습 니 다.즉,Block 입 니 다.
Block
위 템 플 릿 에 들 어가 vue-next 에서 생 성 된 렌 더 링 함 수 는 다음 과 같 습 니 다.
const _Vue = Vue
const { createVNode: _createVNode } = _Vue
const _hoisted_1 = _createVNode("span", { class: "header" }, "I'm header", -1 /* HOISTED */)
const _hoisted_2 = _createVNode("li", null, " li", -1 /* HOISTED */)
return function render(_ctx, _cache) {
with (_ctx) {
const { createVNode: _createVNode, renderList: _renderList, Fragment: _Fragment, openBlock: _openBlock, createBlock: _createBlock, toDisplayString: _toDisplayString } = _Vue
return (_openBlock(), _createBlock(_Fragment, null, [
_hoisted_1,
_createVNode("ul", null, [
_hoisted_2,
(_openBlock(true), _createBlock(_Fragment, null, _renderList(state.mutableItems, (item) => {
return (_openBlock(), _createBlock("li", { key: item.key }, _toDisplayString(item.desc), 1 /* TEXT */))
}), 128 /* KEYED_FRAGMENT */))
])
], 64 /* STABLE_FRAGMENT */))
}
}
우 리 는 openBlock 과 createBlock 방법 을 호출 한 것 을 볼 수 있 습 니 다.이 두 가지 방법의 코드 실현 도 간단 합 니 다.
const blockStack: (VNode[] | null)[] = []
let currentBlock: VNode[] | null = null
let shouldTrack = 1
// openBlock
export function openBlock(disableTracking = false) {
blockStack.push((currentBlock = disableTracking ? null : []))
}
export function createBlock(
type: VNodeTypes | ClassComponent,
props?: { [key: string]: any } | null,
children?: any,
patchFlag?: number,
dynamicProps?: string[]
): VNode {
// avoid a block with patchFlag tracking itself
shouldTrack--
const vnode = createVNode(type, props, children, patchFlag, dynamicProps)
shouldTrack++
// save current block children on the block vnode
vnode.dynamicChildren = currentBlock || EMPTY_ARR
// close block
blockStack.pop()
currentBlock = blockStack[blockStack.length - 1] || null
// a block is always going to be patched, so track it as a child of its
// parent block
if (currentBlock) {
currentBlock.push(vnode)
}
return vnode
}
더 자세 한 설명 은 원본 코드 의 주석 을 보십시오.매우 상세 하 게 써 서 이해 하기 쉽 습 니 다.이 안에 openBlock 은 블록 을 초기 화 하 는 것 입 니 다.createBlock 은 현재 컴 파일 된 내용 에 블록 을 만 드 는 것 입 니 다.이 줄 의 코드 는 vnode.dynamicChildren=currentBlock||EMPTY 입 니 다.ARR 은 동적 인 하위 노드 를 수집 하 는 것 입 니 다.컴 파일 할 때 실행 되 는 함 수 를 다시 볼 수 있 습 니 다.
// createVNode
function _createVNode(
type: VNodeTypes | ClassComponent,
props: (Data & VNodeProps) | null = null,
children: unknown = null,
patchFlag: number = 0,
dynamicProps: string[] | null = null
) {
/**
*
**/
// presence of a patch flag indicates this node needs patching on updates.
// component nodes also should always be patched, because even if the
// component doesn't need to update, it needs to persist the instance on to
// the next vnode so that it can be properly unmounted later.
if (
shouldTrack > 0 &&
currentBlock &&
// the EVENTS flag is only for hydration and if it is the only flag, the
// vnode should not be considered dynamic due to handler caching.
patchFlag !== PatchFlags.HYDRATE_EVENTS &&
(patchFlag > 0 ||
shapeFlag & ShapeFlags.SUSPENSE ||
shapeFlag & ShapeFlags.STATEFUL_COMPONENT ||
shapeFlag & ShapeFlags.FUNCTIONAL_COMPONENT)
) {
currentBlock.push(vnode)
}
}
상기 함 수 는 템 플 릿 을 ast 로 컴 파일 한 후에 호출 된 VNode 를 생 성 하 는 함수 이기 때문에 patchFlag 이라는 표지 가 있 습 니 다.동적 노드 이 고 이때 Block 이 열 리 면 노드 를 Block 에 넣 습 니 다.그러면 createBlock 이 돌아 오 는 VNode 에 dynamic Children 이 있 습 니 다.지금까지 본 논문 에서 사례 를 통 해 템 플 릿 컴 파일 과 render 함수 가 실 행 된 후에 최적화 된 후에 다음 과 같은 구조의 vnode 를 생 성 했다.
const result = {
type: Symbol(Fragment),
patchFlag: 64,
children: [
{ type: 'span', patchFlag: -1, ...},
{
type: 'ul',
patchFlag: 0,
children: [
{ type: 'li', patchFlag: -1, ...},
{
type: Symbol(Fragment),
children: [
{ type: 'li', patchFlag: 1 ...},
{ type: 'li', patchFlag: 1 ...}
]
}
]
}
],
dynamicChildren: [
{
type: Symbol(Fragment),
patchFlag: 128,
children: [
{ type: 'li', patchFlag: 1 ...},
{ type: 'li', patchFlag: 1 ...}
]
}
]
}
이상 의 result 는 완전 하지 않 지만,우 리 는 잠시 이러한 속성 에 만 관심 을 가 집 니 다.result.children 의 첫 번 째 요 소 는 span,patchFlag=-1 이 고 result 는 dynamic Children 배열 이 있 습 니 다.그 안에 두 개의 동적 li 만 포함 되 어 있 습 니 다.나중에 데 이 터 를 바 꾸 면 새로운 vnode.dynamic Children 에는 세 번 째 li 요소 가 있 습 니 다.patch
patch 부분 도 별로 차이 가 없 는데 vnode 의 type 에 따라 서로 다른 patch 작업 을 수행 하 는 것 입 니 다.
function patchElement(n1, n2) {
let { dynamicChildren } = n2
//
if (dynamicChildren) {
patchBlockChildren (
n1.dynamicChildren!,
dynamicChildren,
el,
parentComponent,
parentSuspense,
areChildrenSVG
)
} else if (!optimized) {
// full diff
patchChildren(
n1,
n2,
el,
null,
parentComponent,
parentSuspense,
areChildrenSVG
)
}
}
dynamic Children 이 있 으 면 vue 2.x 버 전의 diff 작업 이 patchBlock Children()로 바 뀌 고 인 자 는 dynamic Children 만 있 습 니 다.즉,정적 으로 diff 작업 을 하지 않 습 니 다.vue-next patch 에 dynamic Children 이 없 으 면 완전한 diff 작업 을 하고 주석 에 적 힌 full diff 의 후속 코드 를 입력 합 니 다.엔 딩
본 고 는 코드 의 실현 차원 에 대해 깊이 설명 하지 않 았 다.첫째,자신의 실력 이 좋 지 않 아서 아직도 소스 코드 를 읽 고 있 기 때문이다.둘째,저 는 개인 적 으로 소스 코드 를 읽 을 때 사소한 부분 에서 착안 하면 안 된다 고 생각 합 니 다.그 다음 에 서 서 서 도 를 보면 각 부분의 역할 을 알 게 된 후에 생각 을 가지 고 소스 코드 를 읽 으 면 얻 을 수 있 는 것 이 더 많 을 것 입 니 다.
Vue 3 에서 VDOM 에 대한 개선 사항 을 자세히 설명 하 는 이 글 은 여기까지 입 니 다.더 많은 Vue 3 VDOM 내용 은 저희 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 읽 어 주시 기 바 랍 니 다.앞으로 도 많은 응원 부 탁 드 리 겠 습 니 다!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
vue-cli v4.5.0을 사용하여 Vue 3 프로젝트 만들기어제 (7/24)에 이 출시되었습니다. 이렇게하면 vue-cli에서 한 번에 Vue 3 프로젝트를 만들 수 있습니다. (지금까지는 Vue 2 프로젝트를 만든 후에 Vue 3으로 업그레이드해야했습니다.) 바로 프로젝트...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.