更新:如何避免舊響應(yīng)覆蓋新任務(wù))
先看一個(gè)常見(jiàn)的時(shí)序問(wèn)題用戶打開(kāi)任務(wù)列表界面發(fā)出第一次查詢。隨后用戶切換篩選條件界面發(fā)出第二次查詢。第二次查詢先返回頁(yè)面顯示了正確的新列表第一次查詢稍后返回如果代碼無(wú)條件賦值就會(huì)把舊列表重新顯示出來(lái)。這個(gè)問(wèn)題并不要求服務(wù)器出錯(cuò)也不需要極端網(wǎng)絡(luò)環(huán)境。只要兩個(gè)請(qǐng)求的耗時(shí)不同就可能出現(xiàn)。把查詢間隔調(diào)長(zhǎng)只能降低出現(xiàn)概率不能改變響應(yīng)亂序的事實(shí)。請(qǐng)求序號(hào)保護(hù)當(dāng)前視圖一種簡(jiǎn)單方式是在發(fā)起請(qǐng)求前增加序號(hào)響應(yīng)返回后比較當(dāng)前序號(hào)。只有仍然對(duì)應(yīng)最新請(qǐng)求的結(jié)果才允許修改界面。序號(hào)應(yīng)按需要隔離不同組件或獨(dú)立查詢不應(yīng)共享同一個(gè)全局序號(hào)否則一個(gè)頁(yè)面刷新可能誤取消另一個(gè)頁(yè)面的結(jié)果。偽代碼可以表達(dá)為先令 currentSequence 加一保存到 localSequence等待查詢完成若 localSequence 不等于 currentSequence 就丟棄結(jié)果。錯(cuò)誤提示與 loading 狀態(tài)也需要同樣的判斷否則舊請(qǐng)求的失敗提示仍可能覆蓋新請(qǐng)求的成功界面。取消請(qǐng)求和拒絕舊結(jié)果不是一回事在支持取消的客戶端中可以在新查詢發(fā)起時(shí)取消舊查詢以減少無(wú)用的傳輸和解析。但取消信號(hào)可能發(fā)出得太晚服務(wù)端也可能已經(jīng)完成處理。因此界面仍應(yīng)保留響應(yīng)序號(hào)校驗(yàn)。對(duì)于產(chǎn)生業(yè)務(wù)副作用的請(qǐng)求更不能把取消請(qǐng)求理解為取消業(yè)務(wù)。關(guān)閉頁(yè)面或中止連接并不代表服務(wù)器回滾。創(chuàng)建、支付、發(fā)布等操作應(yīng)使用各自的業(yè)務(wù)協(xié)議確認(rèn)結(jié)果而不能沿用普通列表查詢的處理方式。任務(wù)重試需要更穩(wěn)定的身份如果任務(wù)允許重試只有任務(wù) ID 通常還不夠。第一次執(zhí)行的遲到響應(yīng)可能在第二次執(zhí)行開(kāi)始后返回??梢詫⑷蝿?wù) ID 與 attempt_id 或執(zhí)行版本一起傳遞客戶端和服務(wù)器都核對(duì)該響應(yīng)是否屬于當(dāng)前嘗試。這里的版本不是顯示用的“第幾次”文字而是狀態(tài)更新的約束。數(shù)據(jù)庫(kù)更新可以要求當(dāng)前版本與請(qǐng)求攜帶版本一致更新行數(shù)為零時(shí)說(shuō)明請(qǐng)求已過(guò)期或狀態(tài)被其他執(zhí)行者推進(jìn)調(diào)用方應(yīng)讀取最新記錄而不是強(qiáng)行覆蓋。狀態(tài)本身也有不可逆的邊界同一次執(zhí)行中已經(jīng)確認(rèn)完成的結(jié)果不應(yīng)被較舊的處理中快照覆蓋??梢栽诤喜?shù)據(jù)時(shí)同時(shí)考慮執(zhí)行身份、狀態(tài)版本和終態(tài)證據(jù)。單看 updated_at 容易受到時(shí)鐘差異、接口緩存與字段格式影響最好由服務(wù)端提供穩(wěn)定的遞增版本或受約束的狀態(tài)轉(zhuǎn)換。這不意味著所有終態(tài)永遠(yuǎn)不能改變。比如業(yè)務(wù)允許撤銷、審核后駁回就應(yīng)把這些動(dòng)作定義為明確事件并記錄新的版本。不能把一條過(guò)期輪詢響應(yīng)和一次真實(shí)撤銷混在同一條覆蓋規(guī)則中。讓測(cè)試覆蓋響應(yīng)順序可以在測(cè)試中準(zhǔn)備兩個(gè)可手動(dòng)完成的 Promise先發(fā)出舊查詢?cè)侔l(fā)出新查詢先完成新查詢最后完成舊查詢。斷言頁(yè)面仍保留新結(jié)果并檢查舊查詢的異常不會(huì)改變提示或 loading。還應(yīng)測(cè)試組件卸載后響應(yīng)返回、篩選條件連續(xù)變化以及任務(wù)重試后上一輪請(qǐng)求才完成。這些用例不需要真實(shí)弱網(wǎng)也不依賴隨機(jī)延遲因而更容易穩(wěn)定復(fù)現(xiàn)。真實(shí)網(wǎng)絡(luò)測(cè)試可作為補(bǔ)充用來(lái)發(fā)現(xiàn)連接、緩存或會(huì)話相關(guān)問(wèn)題。把用戶看到的狀態(tài)變成可信結(jié)果可靠的狀態(tài)展示來(lái)自三個(gè)層次客戶端拒絕過(guò)期視圖響應(yīng)業(yè)務(wù)執(zhí)行使用明確身份服務(wù)端約束狀態(tài)更新順序。分別建立這些邊界比在頁(yè)面上增加越來(lái)越多的刷新按鈕更容易維護(hù)。