Skip to content

noVueAsyncComputed (JavaScript)

Language JavaScript (and super languages)
biome.json
{
"linter": {
"rules": {
"nursery": {
"noVueAsyncComputed": "error"
}
}
}
}

Disallow asynchronous code in Vue computed properties.

Vue calls the function of a computed property and uses the value it returns right away. Asynchronous code finishes later, so its result never becomes the value of the computed property. An async function returns a Promise instead of the value you expect, and code that runs later, like a setTimeout() callback, can’t change what was already returned.

This rule checks the computed properties declared in the computed option of a component, and the functions passed to computed() from vue. It reports:

  • async functions and the await keyword;
  • new Promise(), and calls to Promise functions such as Promise.all() and Promise.resolve();
  • calls to the then(), catch(), and finally() methods of any object;
  • setTimeout(), setInterval(), setImmediate(), and requestAnimationFrame();
  • nextTick() from vue, Vue.nextTick(), and this.$nextTick().

Functions defined inside a computed property aren’t checked, because they don’t run when Vue computes the value.

If you need a value that is loaded asynchronously, store it in a ref() or in data, update it from a watcher or a method, and read it from the computed property. You can also use computedAsync from VueUse.

<script>
export default {
computed: {
async user() {
return fetchUser(this.userId);
},
},
};
</script>
code-block.vue:4:5 lint/nursery/noVueAsyncComputed ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

✖ This computed property is an async function, so it returns a Promise instead of a value.

2 │ export default {
3 │ computed: {
> 4 │ async user() {
│ ^^^^^
5 │ return fetchUser(this.userId);
6 │ },

ℹ Vue uses the value that a computed property returns right away. Asynchronous code finishes later, so its result never becomes the value of the computed property.

ℹ Store the result in a ref() or in data from a watcher or a method, and read it from the computed property instead.

ℹ This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information.

<script>
export default {
computed: {
user() {
return fetchUser(this.userId).then((response) => response.data);
},
},
};
</script>
code-block.vue:5:14 lint/nursery/noVueAsyncComputed ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

✖ This computed property runs asynchronous code.

3 │ computed: {
4 │ user() {
> 5 │ return fetchUser(this.userId).then((response) => response.data);
│ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6 │ },
7 │ },

ℹ Vue uses the value that a computed property returns right away. Asynchronous code finishes later, so its result never becomes the value of the computed property.

ℹ Store the result in a ref() or in data from a watcher or a method, and read it from the computed property instead.

ℹ This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information.

import { computed } from "vue";
const doubled = computed(() => {
setTimeout(() => console.log(count.value), 100);
return count.value * 2;
});
code-block.js:4:3 lint/nursery/noVueAsyncComputed ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

✖ This computed property schedules code to run later.

3 │ const doubled = computed(() => {
> 4 │ setTimeout(() => console.log(count.value), 100);
│ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
5 │ return count.value * 2;
6 │ });

ℹ Vue uses the value that a computed property returns right away. Asynchronous code finishes later, so its result never becomes the value of the computed property.

ℹ Store the result in a ref() or in data from a watcher or a method, and read it from the computed property instead.

ℹ This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information.

<script>
export default {
computed: {
fullName() {
return `${this.firstName} ${this.lastName}`;
},
loader() {
return async () => fetchUser(this.userId);
},
},
};
</script>

Default: []

Names of objects whose then(), catch(), and finally() methods aren’t reported. Some libraries use these method names for code that isn’t asynchronous. For example, catch() in the Zod validation library sets a fallback value.

The name is the first variable of the chain of calls and property accesses, so "z" matches z.number().catch(0) and z.object({}).shape.catch(0).

biome.json
{
"linter": {
"rules": {
"nursery": {
"noVueAsyncComputed": {
"level": "on",
"options": {
"ignoreObjects": [
"z"
]
}
}
}
}
}
}
import { computed } from "vue";
const age = computed(() => schema.number().catch(0));
code-block.js:3:28 lint/nursery/noVueAsyncComputed ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

✖ This computed property runs asynchronous code.

1 │ import { computed } from "vue";
2 │
> 3 │ const age = computed(() => schema.number().catch(0));
│ ^^^^^^^^^^^^^^^^^^^^^^^^
4 │

ℹ Vue uses the value that a computed property returns right away. Asynchronous code finishes later, so its result never becomes the value of the computed property.

ℹ Store the result in a ref() or in data from a watcher or a method, and read it from the computed property instead.

ℹ This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information.

import { computed } from "vue";
const age = computed(() => z.number().catch(0));