异步操作 #
异步操作模式 #
基本模式 #
javascript
actions: {
async fetchData({ commit }) {
commit('SET_LOADING', true)
try {
const data = await api.fetchData()
commit('SET_DATA', data)
return data
} catch (error) {
commit('SET_ERROR', error.message)
throw error
} finally {
commit('SET_LOADING', false)
}
}
}
完整的错误处理 #
javascript
actions: {
async fetchUser({ commit }, userId) {
commit('SET_LOADING', true)
commit('CLEAR_ERROR')
try {
const response = await fetch(`/api/users/${userId}`)
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`)
}
const user = await response.json()
commit('SET_USER', user)
return { success: true, data: user }
} catch (error) {
commit('SET_ERROR', {
message: error.message,
timestamp: Date.now()
})
return { success: false, error: error.message }
} finally {
commit('SET_LOADING', false)
}
}
}
并发请求 #
Promise.all #
javascript
actions: {
async fetchDashboard({ commit }) {
commit('SET_LOADING', true)
try {
const [users, products, orders] = await Promise.all([
api.fetchUsers(),
api.fetchProducts(),
api.fetchOrders()
])
commit('SET_USERS', users)
commit('SET_PRODUCTS', products)
commit('SET_ORDERS', orders)
return { users, products, orders }
} catch (error) {
commit('SET_ERROR', error.message)
throw error
} finally {
commit('SET_LOADING', false)
}
}
}
并发控制 #
javascript
actions: {
async fetchAllProducts({ commit }, productIds) {
commit('SET_LOADING', true)
// 限制并发数量
const limit = 5
const results = []
for (let i = 0; i < productIds.length; i += limit) {
const batch = productIds.slice(i, i + limit)
const batchResults = await Promise.all(
batch.map(id => api.fetchProduct(id))
)
results.push(...batchResults)
}
commit('SET_PRODUCTS', results)
commit('SET_LOADING', false)
return results
}
}
顺序请求 #
链式调用 #
javascript
actions: {
async fetchUserPosts({ commit }, userId) {
commit('SET_LOADING', true)
try {
// 先获取用户
const user = await api.fetchUser(userId)
commit('SET_USER', user)
// 再获取用户的文章
const posts = await api.fetchUserPosts(userId)
commit('SET_POSTS', posts)
return { user, posts }
} catch (error) {
commit('SET_ERROR', error.message)
throw error
} finally {
commit('SET_LOADING', false)
}
}
}
依赖请求 #
javascript
actions: {
async fetchPostWithComments({ commit }, postId) {
commit('SET_LOADING', true)
try {
// 获取文章
const post = await api.fetchPost(postId)
commit('SET_POST', post)
// 根据文章作者获取作者信息
const author = await api.fetchUser(post.authorId)
commit('SET_AUTHOR', author)
// 获取文章评论
const comments = await api.fetchComments(postId)
commit('SET_COMMENTS', comments)
return { post, author, comments }
} catch (error) {
commit('SET_ERROR', error.message)
throw error
} finally {
commit('SET_LOADING', false)
}
}
}
重试机制 #
基本重试 #
javascript
actions: {
async fetchWithRetry({ commit }, { url, maxRetries = 3 }) {
let lastError
for (let i = 0; i < maxRetries; i++) {
try {
const response = await fetch(url)
if (!response.ok) throw new Error('Request failed')
const data = await response.json()
commit('SET_DATA', data)
return data
} catch (error) {
lastError = error
console.log(`Retry ${i + 1}/${maxRetries}`)
await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)))
}
}
commit('SET_ERROR', lastError.message)
throw lastError
}
}
指数退避 #
javascript
actions: {
async fetchWithBackoff({ commit }, { url, maxRetries = 3 }) {
let lastError
for (let i = 0; i < maxRetries; i++) {
try {
const response = await fetch(url)
if (!response.ok) throw new Error('Request failed')
const data = await response.json()
commit('SET_DATA', data)
return data
} catch (error) {
lastError = error
const delay = Math.pow(2, i) * 1000 // 1s, 2s, 4s...
await new Promise(resolve => setTimeout(resolve, delay))
}
}
throw lastError
}
}
取消请求 #
使用 AbortController #
javascript
// store.js
let abortController = null
actions: {
async fetchProducts({ commit }, filters) {
// 取消之前的请求
if (abortController) {
abortController.abort()
}
abortController = new AbortController()
commit('SET_LOADING', true)
try {
const response = await fetch('/api/products', {
signal: abortController.signal,
body: JSON.stringify(filters)
})
const products = await response.json()
commit('SET_PRODUCTS', products)
return products
} catch (error) {
if (error.name === 'AbortError') {
console.log('Request cancelled')
return
}
commit('SET_ERROR', error.message)
throw error
} finally {
commit('SET_LOADING', false)
abortController = null
}
}
}
防抖和节流 #
防抖搜索 #
javascript
let searchTimeout = null
actions: {
async searchProducts({ commit }, query) {
// 清除之前的定时器
if (searchTimeout) {
clearTimeout(searchTimeout)
}
// 防抖 300ms
return new Promise((resolve) => {
searchTimeout = setTimeout(async () => {
commit('SET_SEARCH_QUERY', query)
commit('SET_LOADING', true)
try {
const results = await api.searchProducts(query)
commit('SET_SEARCH_RESULTS', results)
resolve(results)
} catch (error) {
commit('SET_ERROR', error.message)
} finally {
commit('SET_LOADING', false)
}
}, 300)
})
}
}
轮询 #
定时轮询 #
javascript
let pollingInterval = null
actions: {
startPolling({ dispatch }, { endpoint, interval = 5000 }) {
// 停止之前的轮询
dispatch('stopPolling')
// 立即执行一次
dispatch('fetchData', endpoint)
// 设置定时轮询
pollingInterval = setInterval(() => {
dispatch('fetchData', endpoint)
}, interval)
},
stopPolling() {
if (pollingInterval) {
clearInterval(pollingInterval)
pollingInterval = null
}
},
async fetchData({ commit }, endpoint) {
try {
const data = await api.fetch(endpoint)
commit('SET_DATA', data)
} catch (error) {
console.error('Polling error:', error)
}
}
}
实战示例 #
完整的数据获取流程 #
javascript
// store/modules/posts.js
export default {
namespaced: true,
state: {
items: [],
current: null,
pagination: {
page: 1,
perPage: 10,
total: 0
},
loading: false,
error: null
},
mutations: {
SET_ITEMS(state, items) {
state.items = items
},
APPEND_ITEMS(state, items) {
state.items = [...state.items, ...items]
},
SET_CURRENT(state, item) {
state.current = item
},
SET_PAGINATION(state, pagination) {
state.pagination = { ...state.pagination, ...pagination }
},
SET_LOADING(state, loading) {
state.loading = loading
},
SET_ERROR(state, error) {
state.error = error
}
},
actions: {
// 获取列表
async fetchList({ commit, state }, { page = 1, refresh = false } = {}) {
if (refresh) {
commit('SET_ITEMS', [])
}
commit('SET_LOADING', true)
commit('SET_ERROR', null)
try {
const response = await api.getPosts({
page,
perPage: state.pagination.perPage
})
if (refresh || page === 1) {
commit('SET_ITEMS', response.items)
} else {
commit('APPEND_ITEMS', response.items)
}
commit('SET_PAGINATION', {
page: response.page,
total: response.total
})
return response.items
} catch (error) {
commit('SET_ERROR', error.message)
throw error
} finally {
commit('SET_LOADING', false)
}
},
// 加载更多
async loadMore({ dispatch, state }) {
if (state.loading) return
if (state.items.length >= state.pagination.total) return
return dispatch('fetchList', {
page: state.pagination.page + 1
})
},
// 获取详情
async fetchDetail({ commit }, id) {
commit('SET_LOADING', true)
commit('SET_ERROR', null)
try {
const post = await api.getPost(id)
commit('SET_CURRENT', post)
return post
} catch (error) {
commit('SET_ERROR', error.message)
throw error
} finally {
commit('SET_LOADING', false)
}
},
// 创建
async create({ commit }, data) {
commit('SET_LOADING', true)
try {
const post = await api.createPost(data)
commit('SET_CURRENT', post)
return post
} catch (error) {
commit('SET_ERROR', error.message)
throw error
} finally {
commit('SET_LOADING', false)
}
},
// 更新
async update({ commit }, { id, data }) {
commit('SET_LOADING', true)
try {
const post = await api.updatePost(id, data)
commit('SET_CURRENT', post)
return post
} catch (error) {
commit('SET_ERROR', error.message)
throw error
} finally {
commit('SET_LOADING', false)
}
},
// 删除
async remove({ commit, state }, id) {
commit('SET_LOADING', true)
try {
await api.deletePost(id)
commit('SET_CURRENT', null)
commit('SET_ITEMS', state.items.filter(p => p.id !== id))
} catch (error) {
commit('SET_ERROR', error.message)
throw error
} finally {
commit('SET_LOADING', false)
}
}
}
}
总结 #
异步操作要点:
| 模式 | 说明 |
|---|---|
| 错误处理 | try/catch + finally |
| 并发请求 | Promise.all |
| 顺序请求 | await 链式调用 |
| 重试机制 | 循环 + 延迟 |
| 取消请求 | AbortController |
| 防抖节流 | setTimeout/clearTimeout |
继续学习 组合Action,了解如何组合多个 Action。
最后更新:2026-03-28