23k star超火項(xiàng)目,請(qǐng)求優(yōu)化寫的一塌糊涂!我直接重構(gòu)!
取消重復(fù)請(qǐng)求
取消重復(fù)請(qǐng)求是一個(gè)前端項(xiàng)目中很常見的網(wǎng)絡(luò)請(qǐng)求優(yōu)化手段,他主要是為了防止短時(shí)間內(nèi)發(fā)送了多個(gè)一模一樣的請(qǐng)求,導(dǎo)致性能的消耗~
23k star 的項(xiàng)目是怎么做的?
github 上有一個(gè)很火的項(xiàng)目,叫做 Vben-Admin,是一個(gè)非常出色的后臺(tái)管理系統(tǒng)模板,但是個(gè)人覺得它的取消重復(fù)請(qǐng)求做的一塌糊涂(下面會(huì)說理由)?。?!
由于項(xiàng)目中源代碼比較多,我盡量簡(jiǎn)化了代碼,給大家展示一下它是怎么去實(shí)現(xiàn)這個(gè)功能的
我先說一下它實(shí)現(xiàn)這個(gè)功能的思路:
- 1、維護(hù)一個(gè) Map:key 是 請(qǐng)求的 Method + Url,value 是這個(gè)請(qǐng)求的取消方法
- 2、請(qǐng)求攔截器中:先清除掉 Map 中此請(qǐng)求 Method + Url 的存儲(chǔ),也就是取消掉前面的重復(fù)請(qǐng)求,然后再進(jìn)行本次請(qǐng)求
- 3、響應(yīng)攔截器:清除掉本次請(qǐng)求的存儲(chǔ),確保不影響下一次的判斷
簡(jiǎn)化后的代碼如下
圖片
接著在頁(yè)面中使用
圖片
假如我點(diǎn)擊了三次,那么它會(huì)將我前面的兩次取消掉,只讓第三次請(qǐng)求成功,從而實(shí)現(xiàn)取消重復(fù)請(qǐng)求的功能~
圖片
圖片
但是這個(gè)方案缺陷真的很大,比如看下面的例子,我不止一個(gè)按鈕調(diào)用了,我有兩個(gè)按鈕去調(diào)用這個(gè)接口
圖片
我先點(diǎn)擊了按鈕1,再點(diǎn)擊按鈕2,發(fā)現(xiàn)它把我按鈕1的請(qǐng)求取消掉了,只請(qǐng)求了按鈕2的請(qǐng)求,其實(shí)這是沒錯(cuò)的,但是錯(cuò)就錯(cuò)在,它取消了按鈕1的請(qǐng)求,但是連著按鈕1點(diǎn)擊事件接下來的代碼都中斷掉了?。。。?/p>
圖片
可以發(fā)現(xiàn),控制臺(tái)沒有打印按鈕1的結(jié)果,只打印了按鈕2的結(jié)果!??!
圖片
這顯然是不合理的,我們?nèi)∠貜?fù)請(qǐng)求只是為了減少網(wǎng)絡(luò)資源、性能的消耗,但是可不想因?yàn)檫@個(gè)優(yōu)化,而影響了我們?cè)镜倪壿媬
其實(shí)上面的按鈕1、按鈕2,也可以類比為頁(yè)面1、頁(yè)面2,兩個(gè)頁(yè)面在短時(shí)間內(nèi)發(fā)起了同一個(gè)請(qǐng)求,你直接去把頁(yè)面1的后續(xù)邏輯都中斷了,這不是一個(gè)好的方案?。。?/p>
并且其實(shí)不合理的地方還有:Method + Url當(dāng)做 key,確實(shí)不太合理(但是本文暫且不關(guān)注這點(diǎn))
自己思考怎么做~
想了一下,不能用上述的方案來做,缺陷太大了,自己想的方式就是不取消請(qǐng)求了!而是直接不發(fā)請(qǐng)求! 大概的思路如下:
- 1、維護(hù)一個(gè)Map:key 是 請(qǐng)求的 Method + Url,value 第一次請(qǐng)求的 Promise
- 2、第一次請(qǐng)求時(shí),生成一個(gè) Promise,存儲(chǔ)在 Map 中
- 3、第一次請(qǐng)求響應(yīng)之后,修改 Promise 的狀態(tài),并把響應(yīng)數(shù)據(jù)傳給 Promise
- 4、后續(xù)的重復(fù)請(qǐng)求以第一次請(qǐng)求的 Promise 為準(zhǔn),確保能復(fù)用數(shù)據(jù),且不影響各自的后續(xù)邏輯
簡(jiǎn)化后的代碼如下:
圖片
結(jié)果如下,按鈕1、按鈕2各自的后續(xù)邏輯會(huì)繼續(xù)進(jìn)行
圖片
且請(qǐng)求只會(huì)發(fā)出一次
圖片
第一個(gè)請(qǐng)求報(bào)錯(cuò)了咋辦?
我這個(gè)方案是以第一個(gè)請(qǐng)求為主的,那么,如果第一個(gè)請(qǐng)求失敗了,那后續(xù)的重復(fù)請(qǐng)求就爺跟著失敗嗎?顯然是不對(duì)的~
第一個(gè)請(qǐng)求失敗之后,我們必須讓后續(xù)的請(qǐng)求再重新走一次流程才對(duì),就像是一切都沒發(fā)生過一樣!
只需要在后續(xù)重復(fù)請(qǐng)求的錯(cuò)誤回調(diào)中,重新執(zhí)行請(qǐng)求即可,這樣又能重新來過了?。。?/p>
圖片
可以看到,就算前面的失敗了,后面的照樣能自己發(fā)起請(qǐng)求進(jìn)行自救
圖片
圖片
有完善的空間
以上只是我根據(jù)自己思路寫出的一個(gè)粗略版本,如果大家有自己其他的顧慮,可以進(jìn)行修改精進(jìn)!