refactor(reactivity): use more efficient reactive checks
WeakSets and WeakMaps shows degrading performance as the amount of observed objects increases. Using hidden keys result in better performance especially when repeatedly creating large amounts of reactive proxies. This also makes it possible to more efficiently declare non-reactive objects in userland.
This commit is contained in:
@@ -4,8 +4,7 @@ import {
|
||||
ReactiveEffect,
|
||||
pauseTracking,
|
||||
resetTracking,
|
||||
shallowReadonly,
|
||||
markRaw
|
||||
shallowReadonly
|
||||
} from '@vue/reactivity'
|
||||
import {
|
||||
ComponentPublicInstance,
|
||||
@@ -464,7 +463,7 @@ function setupStatefulComponent(
|
||||
instance.accessCache = {}
|
||||
// 1. create public instance / render proxy
|
||||
// also mark it raw so it's never observed
|
||||
instance.proxy = markRaw(new Proxy(instance.ctx, PublicInstanceProxyHandlers))
|
||||
instance.proxy = new Proxy(instance.ctx, PublicInstanceProxyHandlers)
|
||||
if (__DEV__) {
|
||||
exposePropsOnRenderContext(instance)
|
||||
}
|
||||
|
||||
@@ -6,7 +6,8 @@ import {
|
||||
ReactiveEffect,
|
||||
UnwrapRef,
|
||||
toRaw,
|
||||
shallowReadonly
|
||||
shallowReadonly,
|
||||
ReactiveFlags
|
||||
} from '@vue/reactivity'
|
||||
import {
|
||||
ExtractComputedReturns,
|
||||
@@ -128,6 +129,11 @@ export const PublicInstanceProxyHandlers: ProxyHandler<any> = {
|
||||
appContext
|
||||
} = instance
|
||||
|
||||
// let @vue/reatvitiy know it should never observe Vue public instances.
|
||||
if (key === ReactiveFlags.skip) {
|
||||
return true
|
||||
}
|
||||
|
||||
// data / props / ctx
|
||||
// This getter gets called for every property access on the render context
|
||||
// during render and is a major hotspot. The most expensive part of this
|
||||
@@ -197,10 +203,9 @@ export const PublicInstanceProxyHandlers: ProxyHandler<any> = {
|
||||
} else if (
|
||||
__DEV__ &&
|
||||
currentRenderingInstance &&
|
||||
// #1091 avoid isRef/isVNode checks on component instance leading to
|
||||
// infinite warning loop
|
||||
key !== '_isRef' &&
|
||||
key !== '_isVNode'
|
||||
// #1091 avoid internal isRef/isVNode checks on component instance leading
|
||||
// to infinite warning loop
|
||||
key.indexOf('__v') !== 0
|
||||
) {
|
||||
if (data !== EMPTY_OBJ && key[0] === '$' && hasOwn(data, key)) {
|
||||
warn(
|
||||
|
||||
@@ -46,7 +46,7 @@ h(Component, null, {})
|
||||
|
||||
type RawProps = VNodeProps & {
|
||||
// used to differ from a single VNode object as children
|
||||
_isVNode?: never
|
||||
__v_isVNode?: never
|
||||
// used to differ from Array children
|
||||
[Symbol.iterator]?: never
|
||||
}
|
||||
|
||||
@@ -103,7 +103,14 @@ export type VNodeNormalizedChildren =
|
||||
| null
|
||||
|
||||
export interface VNode<HostNode = RendererNode, HostElement = RendererElement> {
|
||||
_isVNode: true
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
__v_isVNode: true
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
__v_skip: true
|
||||
type: VNodeTypes
|
||||
props: VNodeProps | null
|
||||
key: string | number | null
|
||||
@@ -221,7 +228,7 @@ export function createBlock(
|
||||
}
|
||||
|
||||
export function isVNode(value: any): value is VNode {
|
||||
return value ? value._isVNode === true : false
|
||||
return value ? value.__v_isVNode === true : false
|
||||
}
|
||||
|
||||
export function isSameVNodeType(n1: VNode, n2: VNode): boolean {
|
||||
@@ -344,7 +351,8 @@ function _createVNode(
|
||||
}
|
||||
|
||||
const vnode: VNode = {
|
||||
_isVNode: true,
|
||||
__v_isVNode: true,
|
||||
__v_skip: true,
|
||||
type,
|
||||
props,
|
||||
key: props && normalizeKey(props),
|
||||
@@ -403,7 +411,8 @@ export function cloneVNode<T, U>(
|
||||
// This is intentionally NOT using spread or extend to avoid the runtime
|
||||
// key enumeration cost.
|
||||
return {
|
||||
_isVNode: true,
|
||||
__v_isVNode: true,
|
||||
__v_skip: true,
|
||||
type: vnode.type,
|
||||
props,
|
||||
key: props && normalizeKey(props),
|
||||
|
||||
Reference in New Issue
Block a user