1. Description of the functional computed
computed
As a computed attribute, its function is to describe the complex logical calculation of responsive data. When the responsive data dependent on changes, the computed attribute will be recalculated and the result of the logical calculation is updated.
There is a feature that reflects the characteristics of computing attributes, which is to compare the differences between computation attributes and methods. For example, we need to calculate the sum of two responsive data.
const obj = new reactive({foo: 1, bar: 2}) // Use the computed attribute to get the valueconst value = computed(() => { + }) // Use method to get the valueconst value = () => +
The difference is that computed has a cache mechanism. When the internally dependent responsive data has not changed, the results are directly obtained from the cache, while the method needs to be executed every time. When there is a lot of responsive data dependent and the logic is very complex, the computational attribute efficiency will be much higher than that of the method.
2. lazy design of computing attributes
For calculation properties we only need to calculate when we need values,computed(getter)
Take onegetter
As a parameter, it needs to be re-execute every time the responsive data dependent on the calculation property is changed.getter
, but every timegetter
Each execution of the calculation attribute is unnecessary because it is run only when the value of the calculated attribute is obtainedgetter
Get the value, so forgetter
The calculations need to be performed lazyly.
The role of the scheduler has been introduced in the previous chapter, so we only need to add one to the schedulerlazy
Just mark
effect(() => { return + }, { // Set lazy mark in the scheduler lazy: true }) function effect(fn, options = {}) { const effectFn = () => { // Omit the code } = options = [] // If there is a cache tag, it will be returned directly if() return effectFn effectFn() } function computed(getter) { // Use getter as a side effect function const effectFn = effect(getter, { lazy: true, }) const obj = { // EffectFn will only be triggered when value is read get value() { return effectFn() } } return }
This way we are only getting the computed properties.value
The side effect function execution will be triggered only when the responsive data is changed, and it will not be executed directly.
3. Calculate attribute cache
Suppose we have the following code based on the above code design
const sum = computed(() => + ) () () ()
at this timeeffectFn
It will be executed three times in a row, but the result is the same each time because the calculation attribute depends on \
The value of , has not changed , so we can directly cache the calculation results.
function computed(getter) { // Used to cache the calculation results let value // Used to mark whether the value needs to be recalculated let dirty = true let effectFn = effect(getter, { lazy: true }) const obj = { get value() { // If you need to recalculate the value if(dirty) { value = effectFn() dirty = false } return value } } return obj }
We obtain it many timesThe value of the value will not be recalculated every time, but there is a very obvious problem in writing this way that the value of the responsive formula we rely on will not be recalculated when it changes, so we
dirty
This tag needs to be associated with the dependent responsive data. The specific approach is todirty
Put it in the scheduler so that the scheduler changes every time the responsive data is changeddirty
Value of
function computed(getter) { // Used to cache the calculation results let value // Used to mark whether the value needs to be recalculated let dirty = true let effectFn = effect(getter, { lazy: true, // When responsive data is modified, the value of dirty is modified when the side effect function is triggered scheduler: () => { dirty = true } }) const obj = { get value() { // If you need to recalculate the value if(dirty) { value = effectFn() dirty = false } return value } } return obj }
In fact, there is another problem that when the calculation attribute is puteffect
When nesting is formed, we changeobj
The value of the outer layer will not triggereffect
Function, i.e.:
// Omit the code...const sum = computed(() => + ) effect(() => { () })
When changing/
The value ofvalue. This does not conform to the application scenario. In the application, the page will be re-rendered when our computing properties change.
The whole problem is analyzedeffect
Nested problems when inner layer responsive data onlygetter
The connection has nothing to do with the outer side effect function, but the innervalue
It is not responsive data or lazy execution, so it will not be related to the outer side effect function. The solution here is to directly and manually associate the results of the calculation properties with the outer side effect function.
function computed(getter) { let value let dirty = true const effectFn = effect(getter, { lazy: true, scheduler: () => { dirty = true // When the responsive data dependent on the calculation attribute changes, the response will be triggered manually trigger(obj, 'value') } }) const obj = { get value() { if(dirty) { value = effectFn() dirty = false } // Manual tracking when reading value track(obj, 'value') return value } } return obj }
This is the end of this article about the design of computed. For more related computed content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!