How computed properties can significantly improve your Vue app performance

Andrey Firsov
curious.andrew
Published in
5 min readMay 18, 2020

--

When you write a Vue component from scratch, there are cases when you can save a lot of performance just following easy rules of thumbs. This is the first article in a series about these rules of thumbs I explored working with Vue. The second article: How splitting on subcomponents can significantly improve your Vue app performance

In this article I’ll show how to place calculations in a template correctly. There are three basic ways to do this:

  1. using inline expression:
<span :class="['sum', {'sum__big': a + b > 5}]">{{ a + b }}</span>

2. using method invocation:

methods: {
getSum() {
return this.a + this.b;
}
...
<span :class="['sum', {'sum__big': getSum() > 5}]">{{ getSum() }}</span>

3. using computed property:

computed: {
sum() {
return this.a + this.b;
}
...
<span :class="['sum', {'sum__big': sum > 5}]">{{ sum }}</span>

And there are plenty of derivative ways including different combinations of these three.

No matter which way you follow, for the end user the result will be the same. But under the hood the result is slightly different. To illustrate the difference, I prepared a simple fiddle.

Here I make Vue to render a sum of 2 digits — 3 and 2 — via three basic ways. Notice that summands are properties of the object, and the object itself is proxied, so every time you access an object’s property it prints in the console which property and object was accessed. Except logging, a proxied object behaves totally the same as the original.

I also put an input field in a template, bound via v-model with vm.text. Notice that vm.text does not influence the result of any calculation.

If you open your console, you’ll see Vue accessing summands properties during initial rendering (btw, you can see it also accessing “system” props __ob__ and _isVue). Now if you try to type something in the input field, you’ll see that every time vm.text changes, Vue accesses terms for inline expression and method invocation, but not for the computed property. If you uncomment the debugger in proxify, you’ll clearly see in your DevTools how Vue recalculates inline expression and invokes a method, even though none of the data their result relies on changed. In a nutshell: Vue performs a lot of excess calculations in case you use inline expressions or method’s invocations. If you have heavy calculations in your template that might be an issue.

If you use computed prop, calculation would be performed during initial render and later would be performed only when data it’s result relies on changed. That is because Vue caches computed properties and tracks data it depends on, but that’s not the case for inline expressions and template method’s invocations. So we get to the point: computed properties are better in terms of performance, than any other possible way to place calculation in your template. This leads us to the following rule of thumb:

Always use computed properties to place calculation in a template

Besides performance, computed properties make your template more semantic and reasonable: it is easier to debug and to maintain your component if you can get the sense of mustaches just from a glance. Probably it is an even more important reason to use them vs inline expressions.

But why does Vue reevaluate everytime method getSum() if it obviously should give the same result?

If you think a little about it, you’ll come to a conclusion that It is obvious for you, not for Vue. Vue does not reflect the meaning of getSum inner code, it just invokes it every time something changes into a component.

But why is it made to work in such a fashion?

Because in theory you might write your method so that its return value depends on external data, for example coming from an http request or stored in a variable outside Vue instance. Or it might depend on some DOM element. Or it might have to perform some other impure action while evaluating, like changing DOM or changing data and you expect it to perform every time something changes.

I have no idea about the reasons you may need such a behavior, but it does not seem totally impossible. In a nutshell: in theory, you might expect it to work in such a fashion in some cases. It’s definitely not the usual case but Vue doesn’t know for sure your intentions, so it invokes it every time just to ensure the correct result if you do expect it to work so. It’s better to overwork than to fail. Here is an example showing how might look getSum in this case:

Ok, but what if lazy reevaluation is exactly what I need?

Most of the time it is the case. As we already seen, for these cases Vue has computed properties. Declaring a computed property as if telling Vue “Hey, Vue! I have to calculate some derivative data from component’s data and, maybe, props. Here is my function for this calculation. It is totally pure and I don’t want you to invoke it every time a single piece of data changes, just when it’s return value affected”.

In fact, your computed property does not necessarily have to be a pure function, but it’s strongly recommended to be. Impurities in computeds make code bug-prone and hard to understand. That’s why a default vue-cli package includes eslint plugin that throws a warning in console when detects impurity in your computeds.

If you feel like writing impure computed prop, probably a better solution would be to use a combination “pure computed + watcher”.

And the last word, about inline expressions. As you probably already guessed, Vue has no idea about what action performs code inside mustaches, so it follows a simple logic: reevaluate it every time something changes, like it does with method’s invocations.

To conclude

Everything we spoke about in this article applies not only for mustache syntaxis, but also for any possible way to put some calculations in the template, e.g. dynamic bindings, like class binding, style binding, or attribute binding. To maximize efficiency they also have to be presented in a template via computed properties.

To sum up, computed property is the best possible way to present dynamic data in a template in terms of efficiency and code readability and should always be preferred to inline expression and method’s invocation.

What optimization tips do you use in your Vue projects? Please share it with me in a comment.

--

--