vue 踩不完的異步之坑及解決
Js 的異步確實(shí)完美地解決了單線程的問(wèn)題,但是同時(shí)也會(huì)帶來(lái)許多問(wèn)題。而且隨著用的框架越來(lái)越多,越來(lái)越復(fù)雜,定位問(wèn)題的難度也隨之上升。
不知為什么,總覺(jué)得Vue 的斷點(diǎn)調(diào)試相比于不使用框架的情況下更難用,這可能也是花了一個(gè)小時(shí)才找到問(wèn)題產(chǎn)生的根源的原因。廢話(huà)少說(shuō),以下便是問(wèn)題產(chǎn)生的全過(guò)程以及查找問(wèn)題的流程與邏輯梳理。
1. 任務(wù)需求分析
1.1 兩個(gè)頁(yè)面,兩個(gè)組件
任務(wù)需求涉及到兩個(gè)頁(yè)面和兩個(gè)組件之間的恩怨糾紛,它們的關(guān)系如下:
1.2 需求描述
- 用戶(hù)管理和權(quán)限管理是兩個(gè)并列的頁(yè)面。
- 點(diǎn)開(kāi)用戶(hù)管理,里是userTable 組件展示出的用戶(hù)列表。
- 點(diǎn)開(kāi)權(quán)限管理頁(yè)面,然后點(diǎn)擊頁(yè)面上的組成員按鈕,彈出modalUserList 彈框組件,modalUserList 中是userTable 組件展示的用戶(hù)列表。
- 點(diǎn)開(kāi)用戶(hù)管理時(shí)展示的是所有的用戶(hù)列表,點(diǎn)開(kāi)權(quán)限管理再點(diǎn)擊組成員時(shí)展示的是屬于該組的成員列表。
2. 功能是如何實(shí)現(xiàn)的?
2.1 以前端思維消化需求
- 兩個(gè)頁(yè)面用到了同一個(gè)組件userTable,但是需要有不同的表現(xiàn)。所以我們需要一個(gè)tabletype 字段來(lái)標(biāo)識(shí)當(dāng)前是哪個(gè)頁(yè)面引用了userTable 組件。
- 用戶(hù)點(diǎn)擊權(quán)限管理頁(yè)面的時(shí)候,他的孫子元素userTable 需要根據(jù)用戶(hù)點(diǎn)擊的記錄id 來(lái)獲取該組的用戶(hù)信息,中間涉及兩層父子組件通信,不太方便,使用vuex 進(jìn)行處理。
2.2 代碼實(shí)現(xiàn) (簡(jiǎn)化版)
- 用戶(hù)管理頁(yè)面引用userTable 組件的代碼
<userTable ? :tableType="1" ? :userList="userList"></userTable>
- 權(quán)限管理頁(yè)面引用modalUserList 組件的代碼
<modalUserList ? @closeModal="CloseModal" ? :id="chosenGroupId" ? :show="showUserList"></modalUserList>
- modalUserList 組件引用userTable 組件的代碼
<userTable ? :tableType="2" ? :userList="userList"></userTable>
- 權(quán)限管理頁(yè)面點(diǎn)擊組成員按鈕時(shí)的代碼
ShowGroupUserList (index, row) { ? this.showUserList = true ? // 通知孫子獲取用戶(hù)列表 ? this.SetAuthGetUserListTrue() // 通知孫子組件發(fā)送ajax 請(qǐng)求獲取數(shù)據(jù) ? this.SetAuthGroupId(row.id) ? // 設(shè)置authGroupId }
- userTable 組件mounted 和watch 代碼
mounted () { ? this.GetUserList() ? // 權(quán)限管理點(diǎn)擊按鈕時(shí)才獲取用戶(hù)列表 ? // 是通過(guò)點(diǎn)擊權(quán)限管理的組成員按鈕進(jìn)入的 ? if (this.authGetUserList) { ? ? this.GetUserListByGroupId(this.authGroupId) ? ? // 重新將刷新設(shè)為false ? ? this.SetAuthGetUserListFalse() ? } }
watch: { ? authGetUserList: function (newV, oldV) { ? ? // 檢查是否需要根據(jù)選擇的權(quán)限組獲取用戶(hù)列表 ? ? if (newV) { ? ? ? console.log(this.tableType) ? ? ? if (this.tableType == 1) { ? ? ? ? this.GetUserList() ? ? ? } else { ? ? ? ? this.GetUserListByGroupId(this.authGroupId) ? ? ? } ? ? ? // 重新將刷新設(shè)為false ? ? ? this.SetAuthGetUserListFalse() ? ? } ? } }
2.3 代碼翻譯
雖然貼了這么多代碼,但是比較碎片化,一時(shí)半會(huì)可能不太好理清楚其中的邏輯所以這里再稍加解釋?zhuān)陨洗a翻譯成中文后大意如下:
- 使用tableType 來(lái)區(qū)分,如果是從用戶(hù)管理頁(yè)面進(jìn)入的,那么userTable 組件直接使用GetUserList 方法獲取所有用戶(hù)列表并顯示。
- 如果是從權(quán)限管理頁(yè)面進(jìn)入的,那么在用戶(hù)點(diǎn)擊組成員按鈕的瞬間,權(quán)限管理頁(yè)面發(fā)送通知告訴userTable 組件使用用戶(hù)選擇的行id 獲取屬于該權(quán)限組的用戶(hù)列表并顯示 (2.2 中最后兩段代碼)。
3. 遇到了什么問(wèn)題?
- 先進(jìn)用戶(hù)管理頁(yè)面,再進(jìn)權(quán)限管理頁(yè)面,點(diǎn)擊組成員按鈕有大概率會(huì)展示所有用戶(hù)列表而不僅僅是該權(quán)限組用戶(hù)列表
- 直接在權(quán)限管理頁(yè)面點(diǎn)擊組成員按鈕有小概率會(huì)展示所有用戶(hù)列表
4. 問(wèn)題是如何解決的?
4.1 問(wèn)題分析
分析一下問(wèn)題的表現(xiàn)形式,針對(duì)問(wèn)題的產(chǎn)生大概有以下兩種猜測(cè):
- 由于tableType 類(lèi)型傳值錯(cuò)誤導(dǎo)致表格顯示數(shù)據(jù)出錯(cuò)。
- 由于異步數(shù)據(jù)加載較慢,本次數(shù)據(jù)還沒(méi)獲取到,彈框就已經(jīng)顯示,顯示內(nèi)容是上次殘留的數(shù)據(jù),本次的數(shù)據(jù)獲取到后由于某種原因沒(méi)有觸發(fā)頁(yè)面重繪。
4.2 開(kāi)始解決
查了一下代碼發(fā)現(xiàn)tableType 傳值并沒(méi)有出現(xiàn)錯(cuò)誤,第一條猜測(cè)不成立,那么大概率就是由于數(shù)據(jù)的異步獲取導(dǎo)致的問(wèn)題了。(雖然想不明白為什么獲取到數(shù)據(jù)后沒(méi)有觸發(fā)頁(yè)面重繪)
可能解決異步問(wèn)題的一個(gè)猜想:等到數(shù)據(jù)加載完成了再顯示彈框,而不是用戶(hù)點(diǎn)擊按鈕的瞬間就顯示(代價(jià)是爺孫組件通信),于是嘗試在孫子組件加載數(shù)據(jù)完成時(shí)才通知爺爺組件顯示彈框(父親組件)。嘗試失敗,因?yàn)槿绻幌蕊@示彈框,孫子組件就沒(méi)有掛載,那就不能跟爺爺組件進(jìn)行通信。
下一步,先顯示父親組件,等孫子組件獲取數(shù)據(jù)成功后再顯示孫子組件。設(shè)想功能成功實(shí)現(xiàn),但是依然沒(méi)有解決權(quán)限管理頁(yè)面會(huì)顯示所有用戶(hù)列表的bug!
4.3 斷點(diǎn)調(diào)試顯神威
這個(gè)時(shí)候才想起來(lái)還是可以用斷點(diǎn)調(diào)試的(使用Vue 以來(lái)基本都是用vue-dev-tools 進(jìn)行調(diào)試了,剛好今天vue-dev-tools 又崩了...)。打斷點(diǎn)一步一步走,發(fā)現(xiàn)在權(quán)限管理點(diǎn)擊了組成員按鈕的時(shí)候依然會(huì)在最后調(diào)用GetUserList 方法而不是GetUserListByGroupId 方法。為啥嘞?
回去看代碼,2.2 中最后兩段代碼,mouted 中的寫(xiě)法,原來(lái)真的是有!問(wèn)題!的!mounted 中的寫(xiě)法看起來(lái)是限先執(zhí)行GetUserList,然后根據(jù)情況執(zhí)行GetUserListByGroupId。可是由于異步的問(wèn)題GetUserListByGroupId 方法獲得返回值的時(shí)間不一定在GetUserList 之后,這就導(dǎo)致了bug 的不穩(wěn)定性,有時(shí)正常,有時(shí)出問(wèn)題了!
修改后的mounted 代碼如下:
mounted () { // 權(quán)限管理根據(jù)權(quán)限組id 獲取用戶(hù)列表 if (this.authGetUserList) { this.GetUserListByGroupId(this.authGroupId) // 重新將刷新設(shè)為false this.SetAuthGetUserListFalse() } else { // 用戶(hù)管理直接獲取所有用戶(hù)列表 this.GetUserList() } }
呵呵噠,異步的坑踩了一個(gè)又一個(gè)!
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
解決前后端分離 vue+springboot 跨域 session+cookie失效問(wèn)題
這篇文章主要介紹了前后端分離 vue+springboot 跨域 session+cookie失效問(wèn)題的解決方法,解決過(guò)程也很簡(jiǎn)單 ,需要的朋友可以參考下2019-05-05vuex實(shí)現(xiàn)數(shù)據(jù)持久化的兩種方案
這兩天在做vue項(xiàng)目存儲(chǔ)個(gè)人信息的時(shí)候,遇到了頁(yè)面刷新后個(gè)人信息數(shù)據(jù)丟失的問(wèn)題,在查閱資料后,我得出兩種解決數(shù)據(jù)丟失,使用數(shù)據(jù)持久化的方法,感興趣的小伙伴跟著小編一起來(lái)看看吧2023-08-08vue3+element-plus動(dòng)態(tài)路由菜單示例代碼
這篇文章主要介紹了vue3+element-plus動(dòng)態(tài)路由菜單示例代碼,代碼簡(jiǎn)單易懂,對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-11-11vue如何通過(guò)button的disabled控制按鈕能否被使用
這篇文章主要介紹了vue如何通過(guò)button的disabled控制按鈕能否被使用,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-04-04查看vue-cli腳手架的版本號(hào)和vue真實(shí)版本號(hào)及詳細(xì)操作命令
本文給大家分享如何查看vue-cli腳手架的版本號(hào)和vue真實(shí)版本號(hào)及詳細(xì)操作過(guò)程,本文給大家講解的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2022-11-11vue-calendar-component 封裝多日期選擇組件的實(shí)例代碼
這篇文章主要介紹了vue-calendar-component 封裝多日期選擇組件,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12