Skip to content

Commit 95d87f1

Browse files
authored
perf: more light-weight computed (#452)
* feat: add customRef * perf: more light-weight computed
1 parent b4e4655 commit 95d87f1

File tree

2 files changed

+89
-19
lines changed

2 files changed

+89
-19
lines changed

src/apis/computed.ts

Lines changed: 56 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
import { getVueConstructor, getCurrentInstance } from '../runtimeContext'
22
import { createRef, Ref } from '../reactivity'
3-
import { defineComponentInstance } from '../utils/helper'
4-
import { warn } from '../utils'
3+
import {
4+
warn,
5+
noopFn,
6+
defineComponentInstance,
7+
getVueInternalClasses,
8+
} from '../utils'
59

610
interface Option<T> {
711
get: () => T
@@ -31,28 +35,61 @@ export function computed<T>(
3135
set = options.set
3236
}
3337

34-
const computedHost = defineComponentInstance(getVueConstructor(), {
35-
computed: {
36-
$$state: {
37-
get,
38-
set,
38+
let computedSetter
39+
let computedGetter
40+
41+
if (vm) {
42+
const { Watcher, Dep } = getVueInternalClasses()
43+
let watcher: any
44+
computedGetter = () => {
45+
if (!watcher) {
46+
watcher = new Watcher(vm, get, noopFn, { lazy: true })
47+
}
48+
if (watcher.dirty) {
49+
watcher.evaluate()
50+
}
51+
if (Dep.target) {
52+
watcher.depend()
53+
}
54+
return watcher.value
55+
}
56+
57+
computedSetter = (v: T) => {
58+
if (__DEV__ && !set) {
59+
warn('Write operation failed: computed value is readonly.', vm!)
60+
return
61+
}
62+
63+
if (set) {
64+
set(v)
65+
}
66+
}
67+
} else {
68+
// fallback
69+
const computedHost = defineComponentInstance(getVueConstructor(), {
70+
computed: {
71+
$$state: {
72+
get,
73+
set,
74+
},
3975
},
40-
},
41-
})
76+
})
77+
78+
computedGetter = () => (computedHost as any).$$state
79+
computedSetter = (v: T) => {
80+
if (__DEV__ && !set) {
81+
warn('Write operation failed: computed value is readonly.', vm!)
82+
return
83+
}
4284

43-
vm && vm.$on('hook:destroyed', () => computedHost.$destroy())
85+
;(computedHost as any).$$state = v
86+
}
87+
}
4488

4589
return createRef<T>(
4690
{
47-
get: () => (computedHost as any).$$state,
48-
set: (v: T) => {
49-
if (__DEV__ && !set) {
50-
warn('Write operation failed: computed value is readonly.', vm!)
51-
return
52-
}
53-
54-
;(computedHost as any).$$state = v
55-
},
91+
get: computedGetter,
92+
set: computedSetter,
5693
},
5794
!set
5895
)

src/utils/helper.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,3 +72,36 @@ export function resolveSlots(
7272

7373
return res
7474
}
75+
76+
let vueInternalClasses:
77+
| {
78+
Watcher: any
79+
Dep: any
80+
}
81+
| undefined
82+
83+
export const getVueInternalClasses = () => {
84+
if (!vueInternalClasses) {
85+
const vm: any = defineComponentInstance(getVueConstructor(), {
86+
computed: {
87+
value() {
88+
return 0
89+
},
90+
},
91+
})
92+
93+
// to get Watcher class
94+
const Watcher = vm._computedWatchers.value.constructor
95+
// to get Dep class
96+
const Dep = vm._data.__ob__.dep.constructor
97+
98+
vueInternalClasses = {
99+
Watcher,
100+
Dep,
101+
}
102+
103+
vm.$destroy()
104+
}
105+
106+
return vueInternalClasses
107+
}

0 commit comments

Comments
 (0)