Here I will share with you some of the knowledge I have summarized on the Internet, I hope it will be helpful to everyone
Starting from the characteristics of computed
computed
What are the most dazzling features?
1. Dependency Tracking
import { reactive, computed } from 'vue'
const state = reactive({
a: 1,
b: 2,
c: 3,
})
const sum = computed(() => {
return state.a + state.b
})
We define a responsive data state
and a computed property , and sum
Vue will automatically track sum
the dependent data and establish corresponding dependencies.state.a
state.b
That is, only state.a
when state.b
the sum changes, it sum
will be recalculated, and state.c
no matter how it changes, sum
it will not be affected at all.
2. Cache
Still the above example, if state.a
the state.b
value is no longer changed after being killed, then sum
when we read it, it will return the result of the last calculation instead of recalculating.
3. Lazy computing
This feature is relatively easy to be ignored. Simply put, it will only be calculated when the calculated property is actually used (read), otherwise we just define a variable.
import { reactive, computed } from 'vue'
const state = reactive({
a: 1,
b: 2,
c: 3
})
const sum = computed(() => {
console.log('执行计算')
return state.a + state.b
})
setTimeout(() => {
// 没有读取sum.value之前,sum不会进行计算
console.log('1-sum', sum.value)
// 我们改变了a的值,但是sum并不会立刻进行计算
state.a = 4
setTimeout(() => {
// 而是要等到再次读取的时候才会触发重新计算
console.log('2-sum', sum.value)
}, 1000)
}, 1000)
Implement computed features one by one
1. Lazy computing
We still effect
do things around functions, and so far, effect
registered callbacks are executed immediately.
const state = reactive({
a: 1,
b: 2,
c: 3
})
// 有没有很像计算属性的感觉
const sum = effect(() => {
console.log('执行计算') // 立刻被打印
const value = state.a + state.b
return value
})
console.log(sum) // undefined
If you want to implement computed
lazy execution, we can refer to the previous article Vue3: It turns out that you have such an "asynchronous update" idea, adding an additional parameter lazy
.
lazy
The function it wants to achieve is: if the value is passed true
, the side effect function will not be executed immediately, but the timing of execution will be returned to the user, and the user decides when to execute it.
of course! We should also return the result of the callback (such as the value above)
As you can imagine, we only need to modify a few lines of code to get computed
a big step closer.
const effect = function (fn, options = {}) {
const effectFn = () => {
// ... 省略
// 新增res存储fn执行的结果
const res = fn()
// ... 省略
// 新增返回结果
return res
}
// ... 省略
// 新增,只有lazy不为true时才会立即执行
if (!options.lazy) {
effectFn()
}
// 新增,返回副作用函数让用户执行
return effectFn
}
test wave
const state = reactive({
a: 1,
b: 2,
c: 3,
});
// 有没有很像计算属性的感觉
const sum = effect(() => {
console.log("执行计算"); // 调用sum函数后被打印
const value = state.a + state.b;
return value;
}, {
lazy: true
});
// 不执行sum函数,effect注册的回调将不会执行
console.log(sum()); // 3
2. Dependency Tracking
We have initially implemented the feature of lazy execution. In order to be computed
more similar, we need to encapsulate a function.
function computed (getter) {
const effectFn = effect(getter, {
lazy: true,
})
const obj = {
get value () {
return effectFn()
}
}
return obj
}
This is a bit so flavorful!
test wave
It can be seen computed
that it only depends on state.a
and state.b
, but not on state.c
. This is due to the responsive system implemented in our previous articles, so when it comes to computing properties, we don’t need to change any code, and it is naturally supported.
However, there is still a small problem. We read it twice sum.value
, but the sum is executed twice, which computed
does not match the characteristics of the cache.
Don't worry, this most important feature will be implemented soon.
const state = reactive({
a: 1,
b: 2,
c: 3
})
const sum = computed(() => {
console.log('执行计算')
return state.a + state.b
})
console.log(sum.value)
console.log(sum.value)
3. Cache
Review computed
the caching features:
- It needs to be recalculated only when the things it depends on change
- Otherwise, the result of the last execution is returned.
In order to cache the result of the last calculation, we need to define a value variable. The key now is how to know that the data it depends on has changed?
function computed (getter) {
const effectFn = effect(getter, {
lazy: true,
})
let value
let dirty = true
const obj = {
get value () {
// 2. 只有数据发生变化了才去重新计算
if (dirty) {
value = effectFn()
dirty = false
}
return value
}
}
return obj
}
const state = reactive({
a: 1,
b: 2,
c: 3
})
const sum = computed(() => {
console.log('执行计算')
return state.a + state.b
})
console.log(sum.value) // 3
console.log(sum.value) // 3
state.a = 4
console.log(sum.value) // 3 答案是错误的
Send task scheduler
It has to be said that task scheduling is so powerful that it can not only realize asynchronous batch update of arrays, but also is essential in computed
and .watch
function computed (getter) {
const effectFn = effect(getter, {
lazy: true,
// 数据发生变化后,不执行注册的回调,而是执行scheduler
scheduler () {
// 数据发生了变化后,则重新设置为dirty,那么下次就会重新计算
dirty = true
}
})
let value
let dirty = true
const obj = {
get value () {
// 2. 只有数据发生变化了才去重新计算
if (dirty) {
value = effectFn()
dirty = false
}
return value
}
}
return obj
}
test wave
const state = reactive({
a: 1,
b: 2,
c: 3
})
const sum = computed(() => {
console.log('执行计算')
return state.a + state.b
})
console.log(sum.value) // 3
console.log(sum.value) // 3
state.a = 4
console.log(sum.value) // 3 答案是错误的
Perfect! ! ! Now the interviewer can no longer trouble me! ! !