Vue Asynchronous Computed Getter
ID |
javascript.vue_async_in_computed |
Severity |
high |
Remediation Complexity |
medium |
Remediation Risk |
low |
Remediation Effort |
medium |
Resource |
Reliability |
Language |
JavaScript |
Tags |
async, reliability, vue |
Description
Reports a Vue computed getter that starts asynchronous work: an async getter, an await, a .then continuation or a fetch.
Only the getter is judged. A setter may do whatever a method may do, and a method or a watcher is exactly where the asynchronous work belongs.
Rationale
// Bad — the property holds a Promise
const user = computed(async () => {
const response = await fetch('/user/' + id.value);
return response.json();
});
-
A computed property holds what its getter returns, and an asynchronous getter returns a Promise. The template renders
[object Promise]where the value was meant to be, or nothing at all, and no error anywhere — the getter did return something. -
The dependency tracking fails too, and less visibly. Vue records the reactive values a getter reads while it runs; anything read after the first
awaitis read on a later tick, when tracking is no longer active. The property stops re-evaluating and looks stale rather than broken. -
The getter has no schedule of its own: Vue re-runs it whenever a dependency changes, so an HTTP request in a getter is one request per invalidation, at a rate the component does not control.
Remediation
Load in a watcher or a method, keep the result in state, and let the computed property derive from that state.
// Good
const user = ref(null);
watch(id, async (value) => {
const response = await fetch('/user/' + value);
user.value = await response.json();
}, { immediate: true });
const displayName = computed(() => user.value?.name ?? 'unknown');