2.4.4
https://jsfiddle.net/kz16r91L/
First computed property accesses a nested array and second computed property accesses the first computed property.
The computed property is cached and the repeated calls returns the result immediately.
The compute function is not called but each access to the computed property is very slow.
Looks like the computed property, that accesses a nested array, is not cached properly.
This is related and explained in https://github.com/vuejs/vue/issues/6284
For now, you can avoid the iteration cost by freezing the Array, if you don't expect it to be mutated. This will no longer be necessary in 3.0 though.
Wait. This is not the cause. The cause is, that the access to an already computed property is very slow. If you put a watcher between two computed properties, then all is working great.
See testBB is now even faster than testAA.
I also did the same in my project and all the changes are still reflected properly, but it is a million times faster.
@SeregPie Your test is wrong because the watcher is called before it: https://jsfiddle.net/ns1n6kwq/1/ I also added a few tests:
object property. As you can see, the value of testBB is not the correct final value in your test, because the watcher hasn't fired yet. In reality, you are still accessing the cached value (and as such you get the same super fast access to the value).
So the results of your test are incorrect and make your think the watcher is called instantly. Also, you are not using deep: true which make your watcher not detecting the potential changes in the nested arrays (unlike the computed property which does by default), so the comparison is wrong too.
The performance issue comes from Vue building the dependencies when evaluating the computed properties: accessing the computed properties multiple times adds even more dependencies and slows down the component.
One thing I did when having this kind of performance heavy computed properties was to just access the computed property once and assign it into a local variable:
myComputed () {
const a = this.myOtherComputed
// use a instead of this.myOtherComputed
}
Example for my proposed solution: https://jsfiddle.net/kLor5ep7/1/
You may find that this is in fact as performant as using a watcher as you can see in this corrected version of your watcher test: https://jsfiddle.net/LrLqmmjr/1/ (The watcher is manually added after the first evaluation of the pTestB computed property so the times are right. It is not added again in the next tests. Also, there is a little overhead compared to the previous without-watcher code because the watcher timer includes the call to test and the Promise constructor.)
Notice the time taken by the watcher to fire and update testB after the new element is added to the array.
tl;dr
Inside your computed properties, use local variables to store the other computed properties and avoid accessing them directly multiple times.
Did someone come up with a solution for the use case, when the problem of a slowdown is accessing such computed property in multiple components (instead of having multiple accesses to a computed in another computed) 😅?
Most helpful comment
@SeregPie Your test is wrong because the watcher is called before it: https://jsfiddle.net/ns1n6kwq/1/ I also added a few tests:
objectproperty. As you can see, the value oftestBBis not the correct final value in your test, because the watcher hasn't fired yet. In reality, you are still accessing the cached value (and as such you get the same super fast access to the value).So the results of your test are incorrect and make your think the watcher is called instantly. Also, you are not using
deep: truewhich make your watcher not detecting the potential changes in the nested arrays (unlike the computed property which does by default), so the comparison is wrong too.The performance issue comes from Vue building the dependencies when evaluating the computed properties: accessing the computed properties multiple times adds even more dependencies and slows down the component.
One thing I did when having this kind of performance heavy computed properties was to just access the computed property once and assign it into a local variable:
Example for my proposed solution: https://jsfiddle.net/kLor5ep7/1/
You may find that this is in fact as performant as using a watcher as you can see in this corrected version of your watcher test: https://jsfiddle.net/LrLqmmjr/1/ (The watcher is manually added after the first evaluation of the
pTestBcomputed property so the times are right. It is not added again in the next tests. Also, there is a little overhead compared to the previous without-watcher code because the watcher timer includes the call totestand the Promise constructor.)Notice the time taken by the watcher to fire and update
testBafter the new element is added to the array.tl;dr
Inside your computed properties, use local variables to store the other computed properties and avoid accessing them directly multiple times.