一、當前存在的問題
目前項目前端請求后台數據的方式是這樣的:
-
頁面中
method
中dispatch
到action
-
action
調用mutation
,請求axios
-
請求到數據后存儲到
state
中 -
頁面中在
computed
中獲取state
,使用watch
監聽到數據變化之后做業務邏輯。
調用流程如圖:
在當前的項目中,這樣的調用方式可以解決異步請求,對於接口的響應速度也很快。但依然有着幾點不足。
1.代碼冗余
頁面中的每一個請求都需要一個method,一個comuputed和一個watch。我們知道computed是計算屬性,是Vue數據驅動的重要實現。但在計算屬性里獲取state這個操作並沒有去"計算"。實際上是用了mapstate獲取了全局的state,計算屬性在這里成了一個state的容器。
2.業務邏輯依賴watch
我們知道watch是監聽器,但是用監聽器去監聽計算屬性(數據驅動的)的變化,是本末倒置了。可以看看Vue官方文檔是如何描述監聽的:
雖然計算屬性在大多數情況下更合適,但有時也需要一個自定義的偵聽器。這就是為什么 Vue 通過 watch 選項提供了一個更通用的方法,來響應數據的變化。當需要在數據變化時執行異步或開銷較大的操作時,這個方式是最有用的。
watch應該是作為computed的補充,而不是代替。所以當前的問題是大量的業務邏輯寫在watch里,而不是在調用接口,數據返回之后立即處理
3.錯誤的mutation使用
為什么是錯誤的呢?我們先看看為什么會有上面兩個錯誤的出現。當我們把axios寫到mutation的時候,我們發現computed獲取到state的數據不是同步的。
二、解決問題
我們理想的情況是希望頁面調用method之后去請求axios,后端數據返回時立即進行業務處理,處理完成之后界面立刻響應渲染。另外請求出錯的時候,我們也希望能有對應的處理。實現上述需求,需要使用Promise
來解決。了解Promise的用法,可以參考這篇文章Promise使用詳解。
使用Promise之后的請求流程變為下圖:
在當前的請求邏輯下,我們可能覺得很疑惑的一點是,為什么刪除的時候需要使用state
?按照Vue的定義,state
應該是一個公共的變量,所以刪除之后的數據我不需要保存到state
,但是為了保持頁面的響應我們只能使用state
來保存,使用computed
去獲取state
,使用watch
去響應數據變化。這樣的步驟明顯是多余的,那么我們看看使用了Promise
之后的代碼是什么樣的,這里以一個刪除功能為例:
首先我們需要在action中寫一個Promise,在Promise中調用axios。理論上我們可以在頁面上直接調用axios,但是由於需要保持API接口與頁面解耦,所以頁面的method方法依然是調用action。
actions:{
/* 刪除資源action,進行了HTTP請求狀態的判斷,頁面請求該方法后需要進行處理*/
async delResBaseInfo(context, id) {
return new Promise(function(resolve, reject) {
axios
.delete(`${api}/${id}`)
.then((response) => {
if (response.status == 200) {
resolve(Immutable.fromJS(response.data));
} else {
reject(Immutable.fromJS(response.data));
}
})
.catch(function(error) {
console.log(error);
});
});
}
}
頁面method的調用函數,里面包含了業務邏輯。
// 刪除數據,調用action的axios請求
deletData(id) {
this.loading = true;
this.$store
.dispatch('resourceBase/delResBaseInfo', id)
.then((response) => {
if (response.get('code') == 1) {
this.getData();
this.loading = false;
successMessage(this, textStandard.deleteSuccess(''));
} else {
errorMessage(this, textStandard.deleteError(''));
}
})
.catch((error) => {
console.log(error);
});
},
使用了Promise之后的代碼得到了簡化,並且因為Promise的特性,異步問題也能完美解決。