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) {
// 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)
}
}
}

View 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
}
}