Асинхронные операции в Vue.js лежат в основе работы с сервером, пользовательскими событиями и реактивным обновлением интерфейса. Любое взаимодействие с API, таймерами, WebSocket или ленивой загрузкой компонентов строится на неблокирующей модели выполнения JavaScript. Vue не управляет асинхронностью напрямую, но предоставляет удобные механизмы для корректной интеграции асинхронного кода в реактивную систему.
Promise и async/await в компонентахНа практике асинхронные запросы чаще всего реализуются через
fetch, axios или аналогичные библиотеки,
возвращающие Promise.
export default {
data() {
return {
users: [],
loading: false,
error: null
}
},
async mounted() {
this.loading = true
try {
const response = await fetch('/api/users')
this.users = await response.json()
} catch (e) {
this.error = e
} finally {
this.loading = false
}
}
}
Ключевые моменты:
await-блоков
корректно отражается в DOM;Promise rejection не перехватывается Vue.Методы компонента поддерживают асинхронность без ограничений. Это удобно при обработке пользовательских действий.
methods: {
async saveForm() {
this.saving = true
try {
await api.save(this.form)
this.success = true
} catch (e) {
this.errorMessage = 'Ошибка сохранения'
} finally {
this.saving = false
}
}
}
Асинхронные методы:
Асинхронные запросы почти всегда сопровождаются состояниями:
На уровне компонента это обычно реализуется через дополнительные реактивные свойства.
<div v-if="loading">Загрузка...</div>
<div v-else-if="error">Ошибка</div>
<ul v-else>
<li v-for="item in items" :key="item.id">
{{ item.name }}
</li>
</ul>
Такой подход позволяет декларативно связать состояние асинхронной операции с отображением.
Классические computed свойства не предназначены для
асинхронного кода. Возврат Promise нарушает ожидаемую
синхронную модель.
Неправильный пример:
computed: {
async user() {
const res = await fetch('/api/user')
return res.json()
}
}
Корректный подход:
data;computed используется для синхронных производных
значений.watch и
асинхронные побочные эффектыНаблюдатели (watch) часто применяются для запуска
асинхронных операций при изменении состояния.
watch: {
query: {
immediate: true,
async handler(newValue) {
this.loading = true
this.results = await searchApi(newValue)
this.loading = false
}
}
}
Особенности:
watch подходит для реакций на конкретные
изменения;При частых изменениях данных (поиск, фильтрация) возможна ситуация, когда более ранний запрос завершается позже нового.
Распространённые решения:
AbortController;let currentRequest = 0
async function loadData(query) {
const requestId = ++currentRequest
const data = await api.fetch(query)
if (requestId === currentRequest) {
this.items = data
}
}
Vue поддерживает ленивую загрузку компонентов, что также является формой асинхронной обработки.
const AsyncComponent = () => import('./HeavyComponent.vue')
Расширенный вариант:
const AsyncComponent = defineAsyncComponent({
loader: () => import('./HeavyComponent.vue'),
loadingComponent: Loader,
errorComponent: ErrorBlock,
delay: 200,
timeout: 3000
})
Это позволяет:
При использовании централизованного хранилища асинхронная логика выносится из компонентов.
actions: {
async fetchPosts({ commit }) {
const posts = await api.getPosts()
commit('setPosts', posts)
}
}
actions: {
async loadUser() {
this.user = await api.getUser()
}
}
Преимущества:
Асинхронный код тесно связан с жизненным циклом компонента. Важно учитывать, что компонент может быть уничтожен до завершения запроса.
Типичная проблема:
Практики защиты:
isMounted;beforeUnmount;let active = true
onMounted(async () => {
const data = await api.load()
if (active) state.data = data
})
onBeforeUnmount(() => {
active = false
})
SuspenseVue 3 предоставляет компонент Suspense для работы с
асинхронными зависимостями.
<Suspense>
<template #default>
<AsyncComponent />
</template>
<template #fallback>
<Loader />
</template>
</Suspense>
Suspense:
Работа с WebSocket, EventSource или подписками требует особого подхода:
onMounted(() => {
socket = new WebSocket(url)
socket.onmess age = e => {
messages.push(JSON.parse(e.data))
}
})
onBeforeUnmount(() => {
socket.close()
})
Асинхронность в этом случае становится постоянным процессом, а не разовой операцией.
Vue позволяет перехватывать ошибки асинхронных операций через глобальные обработчики.
app.config.errorHandler = (err, instance, info) => {
logError(err)
}
Это полезно для:
Асинхронные ошибки не перехватываются автоматически шаблоном, поэтому ответственность за обработку всегда лежит на логике компонента или хранилища.