From 71a0f3e1ef2a1c5452c211712f070bf37e93830e Mon Sep 17 00:00:00 2001 From: Evan You Date: Sat, 14 May 2016 18:45:54 -0400 Subject: [PATCH] optimize internal component instantiation --- flow/options.js | 14 +++++++++++++- src/core/instance/init.js | 32 +++++++++++++++++++++++++------ src/core/instance/state.js | 2 +- src/core/util/options.js | 6 +++++- src/core/vdom/create-component.js | 11 ++--------- 5 files changed, 47 insertions(+), 18 deletions(-) diff --git a/flow/options.js b/flow/options.js index 31686171..b981224a 100644 --- a/flow/options.js +++ b/flow/options.js @@ -1,8 +1,19 @@ +declare type InternalComponentOptions = { + _isComponent: true, + parent: Component, + propsData: ?Object, + _parentVnode: VNode, + _parentListeners: ?Object, + _renderChildren: ?VNodeChildren, + render?: Function, + staticRenderFns?: Array +} + 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, _parentVnode?: VNode, _parentListeners?: ?{ [key: string]: Function | Array }, diff --git a/src/core/instance/init.js b/src/core/instance/init.js index 36e4cae8..f3e98d14 100644 --- a/src/core/instance/init.js +++ b/src/core/instance/init.js @@ -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 + } +} diff --git a/src/core/instance/state.js b/src/core/instance/state.js index e8cb0fe3..c6f99ad3 100644 --- a/src/core/instance/state.js +++ b/src/core/instance/state.js @@ -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 = {} diff --git a/src/core/util/options.js b/src/core/util/options.js index d42ad16a..03e16a7c 100644 --- a/src/core/util/options.js +++ b/src/core/util/options.js @@ -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) diff --git a/src/core/vdom/create-component.js b/src/core/vdom/create-component.js index 768601b5..c55ec0ad 100644 --- a/src/core/vdom/create-component.js +++ b/src/core/vdom/create-component.js @@ -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 - } = { + const options: InternalComponentOptions = { + _isComponent: true, parent, propsData, _parentVnode: vnode,