perf: skip initializer extraction for options objects

This commit is contained in:
Evan You 2018-10-26 12:11:52 -04:00
parent 8db26a504c
commit f142c322e0
4 changed files with 28 additions and 15 deletions

View File

@ -15,13 +15,17 @@ export interface ComponentClassOptions<P = {}, This = ComponentInstance> {
computed?: ComponentComputedOptions<This>
watch?: ComponentWatchOptions<This>
displayName?: string
fromOptions?: boolean
}
export interface ComponentOptions<
P = {},
D = {},
This = ComponentInstance<P, D>
> extends ComponentClassOptions<P, This>, APIMethods<P, D>, LifecycleMethods {
>
extends ComponentClassOptions<P, This>,
Partial<APIMethods<P, D>>,
Partial<LifecycleMethods> {
// TODO other options
readonly [key: string]: any
}
@ -161,10 +165,7 @@ export function mergeComponentOptions(to: any, from: any): ComponentOptions {
if (isFunction(value) && isFunction(existing)) {
if (key === 'data') {
// for data we need to merge the returned value
// TODO: backwards compat requires recursive merge
res[key] = function() {
return Object.assign(existing.call(this), value.call(this))
}
res[key] = mergeDataFn(existing, value)
} else if (/^render|^errorCaptured/.test(key)) {
// render, renderTracked, renderTriggered & errorCaptured
// are never merged
@ -186,3 +187,11 @@ export function mergeComponentOptions(to: any, from: any): ComponentOptions {
}
return res
}
export function mergeDataFn(a: Function, b: Function): Function {
// TODO: backwards compat requires recursive merge,
// but maybe we should just warn if we detect clashing keys
return function() {
return Object.assign(a.call(this), b.call(this))
}
}

View File

@ -2,10 +2,15 @@ import { ComponentInstance } from './component'
import { observable } from '@vue/observer'
import { isReservedKey } from '@vue/shared'
export function initializeState(instance: ComponentInstance) {
export function initializeState(
instance: ComponentInstance,
shouldExtractInitializers: boolean
) {
const { data } = instance.$options
const rawData = (instance._rawData = (data ? data.call(instance) : {}) as any)
extractInitializers(instance, rawData)
if (shouldExtractInitializers) {
extractInitializers(instance, rawData)
}
instance.$data = observable(rawData || {})
}

View File

@ -45,7 +45,7 @@ export function createComponentInstance<T extends Component>(
$proxy,
$options: { created, computed, watch }
} = instance
initializeState(instance)
initializeState(instance, !Component.fromOptions)
initializeComputed(instance, computed)
initializeWatch(instance, watch)
instance.$slots = currentVNode.slots || EMPTY_OBJ
@ -104,7 +104,7 @@ export function initializeComponentInstance(instance: ComponentInstance) {
export function renderInstanceRoot(instance: ComponentInstance): VNode {
let vnode
try {
vnode = instance.$options.render.call(
vnode = instance.render.call(
instance.$proxy,
instance.$props,
instance.$slots,
@ -209,6 +209,8 @@ export function createComponentClassFromOptions(
): ComponentClass {
class AnonymousComponent extends Component {
static options = options
// indicate this component was created from options
static fromOptions = true
}
const proto = AnonymousComponent.prototype as any
for (const key in options) {

View File

@ -3,7 +3,8 @@ import { createComponentClassFromOptions } from '../componentUtils'
import {
ComponentOptions,
resolveComponentOptionsFromClass,
mergeComponentOptions
mergeComponentOptions,
mergeDataFn
} from '../componentOptions'
import { normalizePropsOptions } from '../componentProps'
import { extractInitializers } from '../componentState'
@ -47,11 +48,7 @@ export function mixins(...args: any[]): any {
return extractInitializers(new Class(this.$props))
}
const { data } = mixin
mixin.data = data
? function() {
return Object.assign(data.call(this), extractData.call(this))
}
: extractData
mixin.data = data ? mergeDataFn(data, extractData) : extractData
} else {
mixin.props = normalizePropsOptions(mixin.props)
}