perf: improve inject performance

This commit is contained in:
Evan You 2019-06-19 22:48:22 +08:00
parent 0952d4cf51
commit 117630fb92
2 changed files with 21 additions and 14 deletions

View File

@ -7,24 +7,29 @@ export function provide<T>(key: Key<T>, value: T | Value<T>) {
if (!currentInstance) { if (!currentInstance) {
// TODO warn // TODO warn
} else { } 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 provides[key as any] = value
} }
} }
export function inject<T>(key: Key<T>): Value<T> | undefined { export function inject<T>(key: Key<T>): Value<T> | undefined {
// traverse parent chain and look for provided value
if (!currentInstance) { if (!currentInstance) {
// TODO warn // TODO warn
} else { } else {
let parent = currentInstance.parent const provides = currentInstance.parent && currentInstance.provides
while (parent) { if (provides) {
const { provides } = parent
if (provides !== null && provides.hasOwnProperty(key as any)) {
const val = provides[key as any] const val = provides[key as any]
return isValue(val) ? val : value(val) return isValue(val) ? val : value(val)
} }
parent = parent.parent
}
} }
} }

View File

@ -112,7 +112,7 @@ export type ComponentInstance<P = Data, S = Data> = {
update: ReactiveEffect update: ReactiveEffect
render: RenderFunction<P, S> | null render: RenderFunction<P, S> | null
effects: ReactiveEffect[] | null effects: ReactiveEffect[] | null
provides: Data | null provides: Data
// the rest are only for stateful components // the rest are only for stateful components
data: S data: S
@ -194,7 +194,7 @@ export function createComponentInstance(
rtc: null, rtc: null,
ec: null, ec: null,
effects: null, effects: null,
provides: null, provides: parent ? parent.provides : {},
// public properties // public properties
data: EMPTY_OBJ, data: EMPTY_OBJ,
@ -225,7 +225,6 @@ export function setupStatefulComponent(instance: ComponentInstance) {
// 2. call setup() // 2. call setup()
const { setup } = Component const { setup } = Component
if (setup) { if (setup) {
currentInstance = instance
// the props proxy makes the props object passed to setup() reactive // the props proxy makes the props object passed to setup() reactive
// so props change can be tracked by watchers // so props change can be tracked by watchers
// it will be updated in resolveProps() on updates before render // it will be updated in resolveProps() on updates before render
@ -234,7 +233,11 @@ export function setupStatefulComponent(instance: ComponentInstance) {
: null) : null)
const setupContext = (instance.setupContext = const setupContext = (instance.setupContext =
setup.length > 1 ? createSetupContext(instance) : null) setup.length > 1 ? createSetupContext(instance) : null)
currentInstance = instance
const setupResult = setup.call(null, propsProxy, setupContext) const setupResult = setup.call(null, propsProxy, setupContext)
currentInstance = null
if (isFunction(setupResult)) { if (isFunction(setupResult)) {
// setup returned an inline render function // setup returned an inline render function
instance.render = setupResult instance.render = setupResult
@ -247,7 +250,6 @@ export function setupStatefulComponent(instance: ComponentInstance) {
} }
instance.render = Component.render as RenderFunction instance.render = Component.render as RenderFunction
} }
currentInstance = null
} }
} }