]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
perf: improve inject performance
authorEvan You <yyx990803@gmail.com>
Wed, 19 Jun 2019 14:48:22 +0000 (22:48 +0800)
committerEvan You <yyx990803@gmail.com>
Wed, 19 Jun 2019 14:48:22 +0000 (22:48 +0800)
packages/runtime-core/src/apiInject.ts
packages/runtime-core/src/component.ts

index 7c9e64eac3331cd74af5483765c358b0a57f37c9..3e266b36e971983e246a139258e32f2ff6a3f0af 100644 (file)
@@ -7,24 +7,29 @@ export function provide<T>(key: Key<T>, value: T | Value<T>) {
   if (!currentInstance) {
     // TODO warn
   } else {
-    const provides = currentInstance.provides || (currentInstance.provides = {})
+    let provides = currentInstance.provides
+    // by default an instance inherits its parent's provides object
+    // but when it needs to provide values of its own, it creates its
+    // own provides object using parent provides object as prototype.
+    // this way in `inject` we can simply look up injections from direct
+    // parent and let the prototype chain do the work.
+    const parentProvides =
+      currentInstance.parent && currentInstance.parent.provides
+    if (parentProvides === provides) {
+      provides = currentInstance.provides = Object.create(parentProvides)
+    }
     provides[key as any] = value
   }
 }
 
 export function inject<T>(key: Key<T>): Value<T> | undefined {
-  // traverse parent chain and look for provided value
   if (!currentInstance) {
     // TODO warn
   } else {
-    let parent = currentInstance.parent
-    while (parent) {
-      const { provides } = parent
-      if (provides !== null && provides.hasOwnProperty(key as any)) {
-        const val = provides[key as any]
-        return isValue(val) ? val : value(val)
-      }
-      parent = parent.parent
+    const provides = currentInstance.parent && currentInstance.provides
+    if (provides) {
+      const val = provides[key as any]
+      return isValue(val) ? val : value(val)
     }
   }
 }
index 35886d68d7141766bfb9012ede6d932a351a6893..35c21568c2a7fcbe287c8f5f87c1f5b784b83eb8 100644 (file)
@@ -112,7 +112,7 @@ export type ComponentInstance<P = Data, S = Data> = {
   update: ReactiveEffect
   render: RenderFunction<P, S> | null
   effects: ReactiveEffect[] | null
-  provides: Data | null
+  provides: Data
 
   // the rest are only for stateful components
   data: S
@@ -194,7 +194,7 @@ export function createComponentInstance(
     rtc: null,
     ec: null,
     effects: null,
-    provides: null,
+    provides: parent ? parent.provides : {},
 
     // public properties
     data: EMPTY_OBJ,
@@ -225,7 +225,6 @@ export function setupStatefulComponent(instance: ComponentInstance) {
   // 2. call setup()
   const { setup } = Component
   if (setup) {
-    currentInstance = instance
     // the props proxy makes the props object passed to setup() reactive
     // so props change can be tracked by watchers
     // it will be updated in resolveProps() on updates before render
@@ -234,7 +233,11 @@ export function setupStatefulComponent(instance: ComponentInstance) {
       : null)
     const setupContext = (instance.setupContext =
       setup.length > 1 ? createSetupContext(instance) : null)
+
+    currentInstance = instance
     const setupResult = setup.call(null, propsProxy, setupContext)
+    currentInstance = null
+
     if (isFunction(setupResult)) {
       // setup returned an inline render function
       instance.render = setupResult
@@ -247,7 +250,6 @@ export function setupStatefulComponent(instance: ComponentInstance) {
       }
       instance.render = Component.render as RenderFunction
     }
-    currentInstance = null
   }
 }