optimize internal component instantiation

This commit is contained in:
Evan You 2016-05-14 18:45:54 -04:00
parent 0dc5d96e3c
commit 71a0f3e1ef
5 changed files with 47 additions and 18 deletions

View File

@ -1,8 +1,19 @@
declare type InternalComponentOptions = {
_isComponent: true,
parent: Component,
propsData: ?Object,
_parentVnode: VNode,
_parentListeners: ?Object,
_renderChildren: ?VNodeChildren,
render?: Function,
staticRenderFns?: Array<Function>
}
declare type ComponentOptions = {
// data
data: Object | Function | void,
props?: { [key: string]: PropOptions },
propsData?: Object,
propsData?: ?Object,
computed?: {
[key: string]: Function | {
get?: Function,
@ -41,6 +52,7 @@ declare type ComponentOptions = {
delimiters?: [string, string],
// private
_isComponent?: true,
_propKeys?: Array<string>,
_parentVnode?: VNode,
_parentListeners?: ?{ [key: string]: Function | Array<Function> },

View File

@ -9,17 +9,24 @@ import { mergeOptions } from '../util/index'
let uid = 0
export function init (vm: Component, options?: ComponentOptions) {
export function init (vm: Component, options?: Object) {
// a uid
vm._uid = uid++
// a flag to avoid this being observed
vm._isVue = true
// merge options
vm.$options = mergeOptions(
vm.constructor.options,
options || {},
vm
)
if (options && options._isComponent) {
// optimize internal component instantiation
// since dynamic options merging is pretty slow, and none of the
// internal component options needs special treatment.
initInternalComponent(vm, options)
} else {
vm.$options = mergeOptions(
vm.constructor.options,
options || {},
vm
)
}
if (process.env.NODE_ENV !== 'production') {
initProxy(vm)
} else {
@ -32,3 +39,16 @@ export function init (vm: Component, options?: ComponentOptions) {
callHook(vm, 'created')
initRender(vm)
}
function initInternalComponent (vm: Component, options: InternalComponentOptions) {
const opts = vm.$options = Object.create(vm.constructor.options)
opts.parent = options.parent
opts.propsData = options.propsData
opts._parentVnode = options._parentVnode
opts._parentListeners = options._parentListeners
opts._renderChildren = options._renderChildren
if (options.render) {
opts.render = options.render
opts.staticRenderFns = opts.staticRenderFns
}
}

View File

@ -46,7 +46,7 @@ function initProps (vm: Component) {
function initData (vm: Component) {
let data = vm.$options.data
data = vm._data = typeof data === 'function'
? data()
? data.call(vm)
: data || {}
if (!isPlainObject(data)) {
data = {}

View File

@ -276,7 +276,11 @@ function guardDirectives (options: Object) {
* Merge two option objects into a new one.
* Core utility used in both instantiation and inheritance.
*/
export function mergeOptions (parent: Object, child: Object, vm?: Component) {
export function mergeOptions (
parent: Object,
child: Object,
vm?: Component
): Object {
guardComponents(child)
guardProps(child)
guardDirectives(child)

View File

@ -77,15 +77,8 @@ export function createComponentInstanceForVnode (
vnode: any // we know it's MountedComponentVNode but flow doesn't
): Component {
const { Ctor, propsData, listeners, parent, children } = vnode.componentOptions
const options: {
parent: Component,
propsData: ?Object,
_parentVnode: VNode,
_parentListeners: ?Object,
_renderChildren: ?VNodeChildren,
render?: Function,
staticRenderFns?: Array<Function>
} = {
const options: InternalComponentOptions = {
_isComponent: true,
parent,
propsData,
_parentVnode: vnode,