perf: optimize props resolution
Store the keys for props that need default or boolean casting during normalization, so that later we only need to iterate through this array instead of the entire props object.
This commit is contained in:
parent
4e91b1328d
commit
2c3c65772b
@ -80,7 +80,9 @@ type NormalizedProp =
|
|||||||
[BooleanFlags.shouldCastTrue]?: boolean
|
[BooleanFlags.shouldCastTrue]?: boolean
|
||||||
})
|
})
|
||||||
|
|
||||||
type NormalizedPropsOptions = Record<string, NormalizedProp>
|
// normalized value is a tuple of the actual normalized options
|
||||||
|
// and an array of prop keys that need value casting (booleans and defaults)
|
||||||
|
type NormalizedPropsOptions = [Record<string, NormalizedProp>, string[]]
|
||||||
|
|
||||||
// resolve raw VNode data.
|
// resolve raw VNode data.
|
||||||
// - filter out reserved keys (key, ref, slots)
|
// - filter out reserved keys (key, ref, slots)
|
||||||
@ -96,11 +98,11 @@ export function resolveProps(
|
|||||||
_options: ComponentPropsOptions | void
|
_options: ComponentPropsOptions | void
|
||||||
) {
|
) {
|
||||||
const hasDeclaredProps = _options != null
|
const hasDeclaredProps = _options != null
|
||||||
const options = normalizePropsOptions(_options)!
|
|
||||||
if (!rawProps && !hasDeclaredProps) {
|
if (!rawProps && !hasDeclaredProps) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { 0: options, 1: needCastKeys } = normalizePropsOptions(_options)!
|
||||||
const props: Data = {}
|
const props: Data = {}
|
||||||
let attrs: Data | undefined = void 0
|
let attrs: Data | undefined = void 0
|
||||||
|
|
||||||
@ -135,9 +137,10 @@ export function resolveProps(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// set default values, cast booleans & run validators
|
|
||||||
if (hasDeclaredProps) {
|
if (hasDeclaredProps) {
|
||||||
for (const key in options) {
|
// set default values & cast booleans
|
||||||
|
for (let i = 0; i < needCastKeys.length; i++) {
|
||||||
|
const key = needCastKeys[i]
|
||||||
let opt = options[key]
|
let opt = options[key]
|
||||||
if (opt == null) continue
|
if (opt == null) continue
|
||||||
const isAbsent = !hasOwn(props, key)
|
const isAbsent = !hasOwn(props, key)
|
||||||
@ -159,15 +162,19 @@ export function resolveProps(
|
|||||||
setProp(key, true)
|
setProp(key, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// runtime validation
|
}
|
||||||
|
// validation
|
||||||
if (__DEV__ && rawProps) {
|
if (__DEV__ && rawProps) {
|
||||||
|
for (const key in options) {
|
||||||
|
let opt = options[key]
|
||||||
|
if (opt == null) continue
|
||||||
let rawValue
|
let rawValue
|
||||||
if (!(key in rawProps) && hyphenate(key) in rawProps) {
|
if (!(key in rawProps) && hyphenate(key) in rawProps) {
|
||||||
rawValue = rawProps[hyphenate(key)]
|
rawValue = rawProps[hyphenate(key)]
|
||||||
} else {
|
} else {
|
||||||
rawValue = rawProps[key]
|
rawValue = rawProps[key]
|
||||||
}
|
}
|
||||||
validateProp(key, toRaw(rawValue), opt, isAbsent)
|
validateProp(key, toRaw(rawValue), opt, !hasOwn(props, key))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -197,19 +204,22 @@ export function resolveProps(
|
|||||||
instance.attrs = options ? attrs || EMPTY_OBJ : props
|
instance.attrs = options ? attrs || EMPTY_OBJ : props
|
||||||
}
|
}
|
||||||
|
|
||||||
const normalizationMap = new WeakMap()
|
const normalizationMap = new WeakMap<
|
||||||
|
ComponentPropsOptions,
|
||||||
|
NormalizedPropsOptions
|
||||||
|
>()
|
||||||
|
|
||||||
function normalizePropsOptions(
|
function normalizePropsOptions(
|
||||||
raw: ComponentPropsOptions | void
|
raw: ComponentPropsOptions | void
|
||||||
): NormalizedPropsOptions | null {
|
): NormalizedPropsOptions {
|
||||||
if (!raw) {
|
if (!raw) {
|
||||||
return null
|
return [] as any
|
||||||
}
|
}
|
||||||
if (normalizationMap.has(raw)) {
|
if (normalizationMap.has(raw)) {
|
||||||
return normalizationMap.get(raw)
|
return normalizationMap.get(raw)!
|
||||||
}
|
}
|
||||||
const normalized: NormalizedPropsOptions = {}
|
const options: NormalizedPropsOptions[0] = {}
|
||||||
normalizationMap.set(raw, normalized)
|
const needCastKeys: NormalizedPropsOptions[1] = []
|
||||||
if (isArray(raw)) {
|
if (isArray(raw)) {
|
||||||
for (let i = 0; i < raw.length; i++) {
|
for (let i = 0; i < raw.length; i++) {
|
||||||
if (__DEV__ && !isString(raw[i])) {
|
if (__DEV__ && !isString(raw[i])) {
|
||||||
@ -217,7 +227,7 @@ function normalizePropsOptions(
|
|||||||
}
|
}
|
||||||
const normalizedKey = camelize(raw[i])
|
const normalizedKey = camelize(raw[i])
|
||||||
if (normalizedKey[0] !== '$') {
|
if (normalizedKey[0] !== '$') {
|
||||||
normalized[normalizedKey] = EMPTY_OBJ
|
options[normalizedKey] = EMPTY_OBJ
|
||||||
} else if (__DEV__) {
|
} else if (__DEV__) {
|
||||||
warn(`Invalid prop name: "${normalizedKey}" is a reserved property.`)
|
warn(`Invalid prop name: "${normalizedKey}" is a reserved property.`)
|
||||||
}
|
}
|
||||||
@ -230,19 +240,25 @@ function normalizePropsOptions(
|
|||||||
const normalizedKey = camelize(key)
|
const normalizedKey = camelize(key)
|
||||||
if (normalizedKey[0] !== '$') {
|
if (normalizedKey[0] !== '$') {
|
||||||
const opt = raw[key]
|
const opt = raw[key]
|
||||||
const prop: NormalizedProp = (normalized[normalizedKey] =
|
const prop: NormalizedProp = (options[normalizedKey] =
|
||||||
isArray(opt) || isFunction(opt) ? { type: opt } : opt)
|
isArray(opt) || isFunction(opt) ? { type: opt } : opt)
|
||||||
if (prop != null) {
|
if (prop != null) {
|
||||||
const booleanIndex = getTypeIndex(Boolean, prop.type)
|
const booleanIndex = getTypeIndex(Boolean, prop.type)
|
||||||
const stringIndex = getTypeIndex(String, prop.type)
|
const stringIndex = getTypeIndex(String, prop.type)
|
||||||
prop[BooleanFlags.shouldCast] = booleanIndex > -1
|
prop[BooleanFlags.shouldCast] = booleanIndex > -1
|
||||||
prop[BooleanFlags.shouldCastTrue] = booleanIndex < stringIndex
|
prop[BooleanFlags.shouldCastTrue] = booleanIndex < stringIndex
|
||||||
|
// if the prop needs boolean casting or default value
|
||||||
|
if (booleanIndex > -1 || hasOwn(prop, 'default')) {
|
||||||
|
needCastKeys.push(normalizedKey)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (__DEV__) {
|
} else if (__DEV__) {
|
||||||
warn(`Invalid prop name: "${normalizedKey}" is a reserved property.`)
|
warn(`Invalid prop name: "${normalizedKey}" is a reserved property.`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const normalized: NormalizedPropsOptions = [options, needCastKeys]
|
||||||
|
normalizationMap.set(raw, normalized)
|
||||||
return normalized
|
return normalized
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user