Vue異步請求最佳實踐


一、當前存在的問題

目前項目前端請求后台數據的方式是這樣的:

  1. 頁面中methoddispatchaction

  2. action調用mutation,請求axios

  3. 請求到數據后存儲到state

  4. 頁面中在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的數據不是同步的。

image

二、解決問題

我們理想的情況是希望頁面調用method之后去請求axios,后端數據返回時立即進行業務處理,處理完成之后界面立刻響應渲染。另外請求出錯的時候,我們也希望能有對應的處理。實現上述需求,需要使用Promise來解決。了解Promise的用法,可以參考這篇文章Promise使用詳解

使用Promise之后的請求流程變為下圖:
image

在當前的請求邏輯下,我們可能覺得很疑惑的一點是,為什么刪除的時候需要使用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的特性,異步問題也能完美解決。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM