Bläddra i källkod

optimize internal component instantiation

Evan You 10 år sedan
förälder
incheckning
71a0f3e1ef

+ 13 - 1
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<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> },

+ 26 - 6
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
+  }
+}

+ 1 - 1
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 = {}

+ 5 - 1
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)

+ 2 - 9
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<Function>
-  } = {
+  const options: InternalComponentOptions = {
+    _isComponent: true,
     parent,
     propsData,
     _parentVnode: vnode,