원리 깊이 분석 Vue 의 응답 식 업데이트 가 React 보다 빠 릅 니 다.
우 리 는 Vue 가 응답 식 속성 업데이트 에 대해 수집 에 의존 하 는 현재 구성 요소 만 정확하게 업데이트 하고 하위 구성 요 소 를 재 귀적 으로 업데이트 하지 않 는 다 는 것 을 알 고 있 습 니 다.이것 도 성능 이 강 한 이유 중 하나 입 니 다.
예시
예 를 들 어 이러한 구성 요소:
<template>
<div>
{{ msg }}
<ChildComponent />
</div>
</template>
this.msg='Hello,Changed~'를 실행 할 때 구성 요소 의 업 데 이 트 를 실행 하고 보기 의 렌 더 링 을 다시 시작 합 니 다.그러나
예전 에 저 는 구성 요소 가 나무 라 고 생각 했 기 때문에 이 나 무 를 옮 겨 다 니 며 재 귀적 으로 업데이트 하 는 것 이 당연 하 다 고 생각 했 습 니 다.이 편 은 소스 코드 의 측면 에서 Vue 가 어떻게 정확하게 업 데 이 트 했 는 지 분석 해 드 리 겠 습 니 다.
React 업데이트 입도
한편,React 는 비슷 한 장면 에서 위 에서 아래로 재 귀적 으로 업 데 이 트 를 한 것 이다.즉,React 에 ChildComponent 에 10 층 의 하위 요소 가 있다 면 모든 단계 가 재 귀적 으로 render(수 동 최적화 되 지 않 은 상황 에서)되 는 것 은 성능 상의 재난 이다.(그래서 React 는 Fiber 를 만 들 었 고 비동기 렌 더 링 을 만 들 었 으 며 사실은 본질 적 으로 자신 이 망 친 성능 을 보완 하 는 것 이다).
그들 은 수집 에 의존 하 는 이 시스템 을 사용 할 수 있 습 니까?아 닙 니 다.그들 은 Immutable 의 디자인 사상 을 따 르 기 때문에 원래 의 대상 에서 속성 을 수정 하지 않 습 니 다.그러면 Object.defineProperty 나 Proxy 의 응답 식 의존 수집 체 제 를 바탕 으로 손 을 쓸 수 없습니다.
또한,응답 식 수집 의존 이 없 기 때문에 React 는 모든 하위 구성 요 소 를 재 렌 더 링 할 수 밖 에 없습니다.
Vue 의 업데이트 입도
그럼 Vue 라 는 정확 한 업 데 이 트 는 어떻게 하 는 건 가요?사실 모든 구성 요 소 는 렌 더 링 워 치 를 가지 고 있 습 니 다.현재 구성 요소 의 보기 업 데 이 트 를 관리 하지만 ChildComponent 의 업 데 이 트 를 관리 하지 않 습 니 다.
구체 적 으로 소스 코드 에서 어떻게 실현 되 었 습 니까?
패 치 이 과정 에서 구성 요소 가 ChildComponent 로 업 데 이 트 될 때 patchVnode 로 갑 니 다.이 방법 은 대체적으로 어떤 일 을 했 습 니까?
patchVnode
vnode 의 prepatch 갈 고 리 를 실행 합 니 다.
구성 요소 vnode 만 prepatch 라 는 라 이 프 사이클 이 있 습 니 다.
업데이트 Child Component 방법 으로 갑 니 다.이 child 는 구체 적 으로 무엇 을 말 합 니까?
prepatch (oldVnode: MountedComponentVNode, vnode: MountedComponentVNode) {
const options = vnode.componentOptions
// child ChildComponent vm , this
const child = vnode.componentInstance = oldVnode.componentInstance
updateChildComponent(
child,
options.propsData, // updated props
options.listeners, // updated listeners
vnode, // new parent vnode
options.children // new children
)
},
사실 들 어 오 는 매개 변 수 를 보면 대충 알 아 맞 힐 수 있 습 니 다.바로 했 습 니 다.예 를 들 어 이런 장면:
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<ul>
얼 의 세 개의 li 서브 노드 vnode 에 대해 diff 알고리즘 을 이용 하여 업데이트 하려 면 이 편 은 생략 합 니 다.그리고 여기까지 패 치 Vnode 는 끝 났 습 니 다.일반적인 생각 처럼 하위 구성 요소 트 리 를 재 귀적 으로 업데이트 하지 않 았 습 니 다.
이 는 Vue 의 구성 요소 업데이트 가 구성 요소 자체 에 정확 하 다 는 것 을 의미한다.
하위 구성 요소 라면?
목록 이 이 렇 습 니 다.
<ul>
<component>1</component>
<component>2</component>
<component>3</component>
<ul>
그러면 diff 과정 에서 component 에서 설명 한 props,listeners 등 속성 만 업데이트 하고 구성 요소 내부 에 깊이 들 어가 업데이트 하지 않 습 니 다.메모:구성 요소 내부 에 깊이 들 어가 업데이트 하지 않 습 니 다!(중점 을 두 는 것 도 본 고 에서 말 한 입도 갱신 의 관건 이다)
props 의 업 데 이 트 는 어떻게 렌 더 링 을 촉발 합 니까?
그러면 학생 들 이 물 어 볼 수도 있 습 니 다.하위 구성 요 소 를 재 귀적 으로 업데이트 하지 않 으 면 msg 라 는 응답 요 소 를 props 를 통 해 Child Component 에 전달 하면 어떻게 업데이트 합 니까?
우선,구성 요소 가 props 를 초기 화 할 때 initprops 방법 으로 갑 니 다.
const props = vm._props = {}
for (const key in propsOptions) {
// props
const value = validateProp(key, propsOptions, propsData, vm)
// props
defineReactive(props, key, value)
}
지금까지 실현 되 었 습 니 다.props 필드 변경 납치.즉,응답 식 데이터 가 되 었 습 니 다.그 다음 에 우 리 는 와 유사 합 니 다.props.msg='Changed'동작 을 할 때(물론 우 리 는 이렇게 하지 않 습 니 다.Vue 내부 에서 할 것 입 니 다)보기 업 데 이 트 를 촉발 합 니 다.사실 msg 는 하위 구성 요소 에 전 달 될 때 하위 구성 요소 인 스 턴 스 에 저 장 됩 니 다props 에 서 는 응답 식 속성 으로 정의 되 었 으 며,하위 구성 요소 의 템 플 릿 에 서 는 msg 에 대한 접근 이 로 대 리 됩 니 다.props.msg 가 올 라 갔 기 때문에 자 연 스 럽 게 의존 도 를 정확하게 수집 할 수 있 습 니 다.ChildComponent 가 템 플 릿 에서 도 이 속성 을 읽 으 면 됩 니 다.
부모 구성 요소 가 다시 렌 더 링 될 때 하위 구성 요소 의 props 를 다시 계산 합 니 다.구체 적 으로 는 updateChild Component 에 있 습 니 다.
// update props
if (propsData && vm.$options.props) {
toggleObserving(false)
// props _props
const props = vm._props
const propKeys = vm.$options._propKeys || []
for (let i = 0; i < propKeys.length; i++) {
const key = propKeys[i]
const propOptions: any = vm.$options.props // wtf flow?
// , _props.msg 。
props[key] = validateProp(key, propOptions, propsData, vm)
}
toggleObserving(true)
// keep a copy of raw propsData
vm.$options.propsData = propsData
}
그러면 위 에 설명 되 어 있 는 그 코드 로 인해 msg 의 변 화 는props 의 응답 식 능력 도 하위 구성 요 소 를 다시 렌 더 링 시 켰 습 니 다.지금까지 msg 를 사용 한 구성 요소 만 다시 렌 더 링 되 었 습 니 다.홈 페이지 api 문서 에서 말 한 바 와 같이:
vm.$forceUpdate:Vue 인 스 턴 스 를 다시 렌 더 링 하도록 합 니 다.모든 하위 구성 요소 가 아 닌 인 스 턴 스 자체 와 슬롯 내용 을 삽입 하 는 하위 구성 요소 에 만 영향 을 줍 니 다.
―― vm-forceUpdate 문서
우 리 는 작은 지식 을 알 아야 합 니 다.vm.$forceUpdate 는 본질 적 으로 렌 더 링 워 치 의 재 실행 을 촉발 하 는 것 입 니 다.응답 식 속성 을 수정 하여 업 데 이 트 를 촉발 하 는 원 리 는 똑 같 습 니 다.vm. 만 호출 해 주 었 을 뿐 입 니 다.watcher.update()(편리 한 api 만 제공 하고 디자인 모델 에서 외관 모델 이 라 고 합 니 다)
slot 는 어떻게 업 데 이 트 됩 니까?
여기 서도 세부 사항 을 언급 했 습 니 다.즉,슬롯 내용 을 삽입 하 는 하위 구성 요소 입 니 다.
예 를 들 면
부모 구성 요소 parent-comp 가 있다 고 가정 합 니 다.
<div>
<slot-comp>
<span>{{ msg }}</span>
</slot-comp>
</div>
하위 구성 요소 slot-comp:
<div>
<slot></slot>
</div>
구성 요소 에 slot 업데이트 가 포함 되 어 있 으 며,비교적 특수 한 장면 에 속 합 니 다.이 msg 속성 은 수집 에 의존 할 때 parent-comp 의 렌 더 링 watcher 를 수집 합 니 다.(왜 그런 지 에 대해 서 는 그것 이 있 는 렌 더 링 문맥 을 보면 알 수 있다.)
그럼 우 리 는 msg 가 이때 업데이트 되 었 다 고 상상 합 니 다.
<div>
<slot-comp>
<span>{{ msg }}</span>
</slot-comp>
</div>
이 구성 요 소 는 업데이트 할 때 하위 구성 요소 slot-comp 를 만 났 습 니 다.Vue 의 정확 한 업데이트 전략 에 따 르 면 하위 구성 요 소 는 다시 렌 더 링 되 지 않 습 니 다.그러나 소스 코드 내부 에서 slot-comp 의 prepatch 라 는 hook 를 실행 할 때 updateChild Component 논 리 를 실행 합 니 다.이 함수 내부 에서 slot 요소 가 있 음 을 발견 할 수 있 습 니 다.
prepatch (oldVnode: MountedComponentVNode, vnode: MountedComponentVNode) {
const options = vnode.componentOptions
// child slot-comp vm , this
const child = vnode.componentInstance = oldVnode.componentInstance
updateChildComponent(
child,
options.propsData, // updated props
options.listeners, // updated listeners
vnode, // new parent vnode
options.children // new children
)
},
updateChildComponent 내부 에서
const hasChildren = !!(
// slot
renderChildren || // has new static slots
vm.$options._renderChildren || // has old static slots
parentVnode.data.scopedSlots || // has new scoped slots
vm.$scopedSlots !== emptyObject // has old scoped slots
)
그리고 다음 판단 을 내 려 보도 록 하 겠 습 니 다.
if (hasChildren) {
vm.$slots = resolveSlots(renderChildren, parentVnode.context)
vm.$forceUpdate()
}
slot-comp 구성 요소 vm 인 스 턴 스 의$forceUpdate 를 호출 했 습 니 다.렌 더 링 워 치 는 slot-comp 의 렌 더 링 워 치 에 속 합 니 다.결론 적 으로 이번 msg 의 업 데 이 트 는 parent-comp 의 렌 더 링 뿐만 아니 라 slot 를 가 진 하위 구성 요소 slot-comp 의 렌 더 링 도 촉발 시 켰 습 니 다.
이것 도 단지 두 겹 의 렌 더 링 을 촉발 시 켰 을 뿐이다.만약 slot-comp 내부 에 또 다른 구성 요소 인 slot-child 가 렌 더 링 되 었 다 면,이 때 는 귀속 업 데 이 트 를 하지 않 을 것 이다.(slot-child 구성 요소 만 있 으 면 slot 가 없습니다.
React 의 재 귀적 업데이트 보다 훨씬 낫 지 않 을까요?
작은 이 슈 하나 드릴 게 요.
누군가가 Vue 2.4.2 버 전에 하 나 를 제시 했다issue.아래 장면 에서 bug 가 나타 날 것 이다.
let Child = {
name: "child",
template:
'<div><span>{{ localMsg }}</span><button @click="change">click</button></div>',
data: function() {
return {
localMsg: this.msg
};
},
props: {
msg: String
},
methods: {
change() {
this.$emit("update:msg", "world");
}
}
};
new Vue({
el: "#app",
template: '<child :msg.sync="msg"><child>',
beforeUpdate() {
alert("update twice");
},
data() {
return {
msg: "hello"
};
},
components: {
Child
}
});
구체 적 인 표현 은 click 단 추 를 누 르 면 alert 에서 두 번 의 update twice 가 나 옵 니 다.이것 은 하위 구성 요소 가 data 라 는 함 수 를 실행 하여 구성 요소 의 데 이 터 를 초기 화 할 때 Dep.target(즉,렌 더 링 watcher)을 잘못 수집 하기 때 문 입 니 다.데이터 초기 화 시 기 는 beforeCreated->created 사이 이기 때문에 하위 구성 요소 의 렌 더 링 단계 에 들 어가 지 않 았 기 때문에 Dep.target 은 부모 구성 요소 의 렌 더 링 watcher 입 니 다.
이 로 인해 중복 수집 의존 을 초래 하고 같은 업 데 이 트 를 반복 적 으로 촉발 합 니 다.
어떻게 해 결 했 지?간단 합 니 다.data 함 수 를 실행 한 후에 Dep.target 을 먼저 null 로 설정 하면 됩 니 다.finally 에서 복원 하면 응답 식 데 이 터 를 의존 할 수 없습니다.
export function getData (data: Function, vm: Component): any {
const prevTarget = Dep.target
+ Dep.target = null
try {
return data.call(vm, vm)
} catch (e) {
handleError(e, vm, `data()`)
return {}
+ } finally {
+ Dep.target = prevTarget
}
}
후기만약 에 Dep.target,렌 더 링 watcher 등 개념 에 대해 잘 이해 하지 못 한다 면 제 가 쓴 가장 간단 한 Vue 응답 식 글 을 볼 수 있 습 니 다.읽 기 를 환영 합 니 다.
Vue 의 data,coptute,watch 소스 를 배우 기 위해 가장 간단 한 응답 시스템 을 실현 합 니 다.
본문 도 제Github 블 로그 창고에 저장 되 어 있 습 니 다.구독 과 스타 를 환영 합 니 다.
원리 에 대한 심도 있 는 해석 Vue 의 응답 식 업데이트 가 React 보다 빠 른 글 을 소개 합 니 다.더 많은 Vue 에 대한 응답 식 업데이트 가 React 보다 빠 른 내용 은 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 찾 아 보 세 요.앞으로 많은 응원 부 탁 드 리 겠 습 니 다!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Vue Render 함수로 DOM 노드 코드 인스턴스 만들기render에서createElement 함수를 사용하여 DOM 노드를 만드는 것은 직관적이지 않지만 일부 독립 구성 요소의 디자인에서 특수한 수요를 충족시킬 수 있습니다.간단한 렌더링 예는 다음과 같습니다. 또한 v...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.