詳解JS如何使用Promise緩存網(wǎng)絡(luò)請(qǐng)求
背景與概念
在進(jìn)行網(wǎng)絡(luò)請(qǐng)求的應(yīng)用中,尤其是數(shù)據(jù)變化不頻繁的場(chǎng)景下,緩存是一個(gè)常用而有效的優(yōu)化手段。緩存可以減少網(wǎng)絡(luò)延遲,避免不必要的數(shù)據(jù)傳輸,節(jié)省帶寬,提高用戶體驗(yàn)。但是,不當(dāng)?shù)木彺娌呗钥赡軐?dǎo)致用戶看到過時(shí)的數(shù)據(jù)。因此,實(shí)現(xiàn)一個(gè)合理的緩存策略是非常重要的。
Promise是JavaScript中處理異步操作的一種模式,它代表一個(gè)尚未完成但預(yù)計(jì)將來會(huì)完成的操作。通過Promise,可以將異步操作隊(duì)列化,鏈?zhǔn)教幚?,并在適當(dāng)?shù)臅r(shí)候進(jìn)行錯(cuò)誤處理。
緩存網(wǎng)絡(luò)請(qǐng)求的需求與挑戰(zhàn)
在許多情況下,當(dāng)多個(gè)組件或者頁面需要相同的數(shù)據(jù)時(shí),每個(gè)組件各自發(fā)起網(wǎng)絡(luò)請(qǐng)求顯得非常低效。這需要一種機(jī)制能夠“共享”已經(jīng)發(fā)起的請(qǐng)求,當(dāng)請(qǐng)求完成后,所有需要這份數(shù)據(jù)的組件都能獲得到。同時(shí),若數(shù)據(jù)已經(jīng)在本地緩存,則無需重新發(fā)起網(wǎng)絡(luò)請(qǐng)求,直接使用緩存數(shù)據(jù)即可。
實(shí)現(xiàn)這樣的功能,有如下幾個(gè)挑戰(zhàn):
- 請(qǐng)求的復(fù)用性:避免同一數(shù)據(jù)的重復(fù)請(qǐng)求。
- 請(qǐng)求的并發(fā)管理:針對(duì)相同的數(shù)據(jù)來源同一時(shí)間只發(fā)送一次請(qǐng)求。
- 緩存的合理性:緩存有效數(shù)據(jù),但要避免過時(shí)數(shù)據(jù)的問題。
- 緩存的容錯(cuò)性:當(dāng)請(qǐng)求失敗時(shí),如何處理以及如何通知依賴這份數(shù)據(jù)的其他部分。
Promise緩存網(wǎng)絡(luò)請(qǐng)求的實(shí)現(xiàn)
具體到實(shí)現(xiàn),可以創(chuàng)建一個(gè)緩存對(duì)象,用于存儲(chǔ)已經(jīng)發(fā)起的請(qǐng)求的Promise對(duì)象。在請(qǐng)求發(fā)起前,先檢查緩存中是否已存在相應(yīng)的Promise;如果存在,直接返回該P(yáng)romise;如果不存在,則發(fā)起新的請(qǐng)求,并將請(qǐng)求的Promise存儲(chǔ)到緩存中。
以下是一個(gè)簡化的實(shí)現(xiàn)示例,逐一解釋核心代碼:
import utils from '@/utils'; export const reqThenCacheData = ( name: string ): Promise<void | Promise<utils.ICachedData>> => { // 嘗試獲取緩存數(shù)據(jù) const cache = utils.cacheForData.get(name); // 如果存在緩存,直接返回緩存中的Promise對(duì)象 if (cache) return cache; // 沒有緩存,構(gòu)造請(qǐng)求URL,發(fā)起網(wǎng)絡(luò)請(qǐng)求 const url = `http://*******?name=${name}`; const currentHandler = ( request.get({ url }) as unknown as Promise<Array<utils.ICachedListData>> ) .then((data: Array<utils.ICachedListData>) => { // 對(duì)返回的數(shù)據(jù)進(jìn)行處理,得到一個(gè)子請(qǐng)求列表 const subList: Array<string> = data.map((sub) => { if (sub.is_default === 1) return sub.subName; }); return subList.filter((item) => item); }) .then((subNames: Array<string>) => { // 根據(jù)第一次請(qǐng)求的結(jié)果,構(gòu)建第二次請(qǐng)求的Promise數(shù)組 const subRequestPromises: Array<Promise<utils.ICachedData>> = subNames.map((subName: string) => { const subUrl = `http://*******?subName=${subName}`; return request.get({ url: subUrl }) as unknown as Promise<utils.ICachedData>; }); // 使用Promise.all等待所有子請(qǐng)求完成 return Promise.all(subRequestPromises); }) .then((subData: Array<utils.ICachedData>) => { // 可以進(jìn)一步處理所有子請(qǐng)求的結(jié)果 // 示例僅返回其中一個(gè)子請(qǐng)求結(jié)果 return subData[0]; }) .catch((error) => { console.log('請(qǐng)求數(shù)據(jù)失敗!', error); // 錯(cuò)誤處理:可以決定是否從緩存中移除錯(cuò)誤的Promise utils.cacheForData.delete(name); // 根據(jù)需要,可以在這里拋出錯(cuò)誤或返回一個(gè)默認(rèn)值 throw error; }); // 存入緩存,便于下次直接使用 utils.cacheForData.set(name, currentHandler); return currentHandler; };
緩存邏輯概述
上述代碼演示了基于Promise的網(wǎng)絡(luò)請(qǐng)求緩存機(jī)制。首先,通過調(diào)用cacheForData.get(name)
嘗試獲取緩存中已存在的請(qǐng)求Promise,如果找到,則直接返回,避免重復(fù)請(qǐng)求。
如果緩存中沒有找到請(qǐng)求Promise,那么將發(fā)起一個(gè)新的網(wǎng)絡(luò)請(qǐng)求。請(qǐng)求返回的Promise通過鏈?zhǔn)降?code>.then()方法進(jìn)行處理。這些.then()
方法負(fù)責(zé)對(duì)返回的數(shù)據(jù)進(jìn)行處理和轉(zhuǎn)化,使用者可以根據(jù)實(shí)際情況添加具體的數(shù)據(jù)處理邏輯。
最后,使用catch()
方法處理可能發(fā)生的錯(cuò)誤,并且將當(dāng)前請(qǐng)求的Promise對(duì)象使用cacheForData.set(name, currentHandler)
方法存儲(chǔ)到緩存中,以便后續(xù)重用。
多階段請(qǐng)求處理
上述代碼展示了如何處理一個(gè)需要多次網(wǎng)絡(luò)請(qǐng)求的場(chǎng)景。系統(tǒng)首先檢查緩存中是否有目標(biāo)數(shù)據(jù)的Promise,在緩存未命中時(shí),發(fā)起一個(gè)初始網(wǎng)絡(luò)請(qǐng)求。取得初始數(shù)據(jù)后,提取必要的信息組成新的請(qǐng)求數(shù)組。
利用Promise.all()
方法,可以并行處理多個(gè)網(wǎng)絡(luò)請(qǐng)求,這個(gè)方法返回一個(gè)新的Promise,它將在所有請(qǐng)求完成時(shí)解析。這一過程是Promise緩存實(shí)現(xiàn)的核心,它使得各個(gè)請(qǐng)求之間可以共享狀態(tài),并在全部請(qǐng)求都完成后統(tǒng)一返回結(jié)果。
這種緩存策略的一個(gè)關(guān)鍵優(yōu)勢(shì)在于它的復(fù)用性和并發(fā)管理能力。即使有多個(gè)請(qǐng)求同時(shí)要求相同的資源,由于緩存機(jī)制的存在,真實(shí)的網(wǎng)絡(luò)請(qǐng)求只會(huì)發(fā)生一次。每個(gè)后續(xù)嘗試訪問此數(shù)據(jù)的操作都會(huì)得到一個(gè)掛起的Promise,而非觸發(fā)新的網(wǎng)絡(luò)請(qǐng)求。
緩存及請(qǐng)求細(xì)節(jié)處理
在網(wǎng)絡(luò)請(qǐng)求Promise后串聯(lián)多個(gè).then()
方法時(shí),是在處理與轉(zhuǎn)換原始請(qǐng)求返回的數(shù)據(jù)。示例中,首先處理的是將返回的列表按照特定條件篩選,然后對(duì)篩選后的結(jié)果進(jìn)行進(jìn)一步的請(qǐng)求。這里的關(guān)鍵是Promise.all()
,它確保了同時(shí)處理多個(gè)異步操作。
處理器currentHandler
的最后結(jié)果是一個(gè)新的Promise,它代表了一系列依賴于原始請(qǐng)求并經(jīng)過一定處理的數(shù)據(jù)。這個(gè)Promise作為最終結(jié)果,將被緩存并返回給調(diào)用者。
緩存和請(qǐng)求的一個(gè)重要細(xì)節(jié)是錯(cuò)誤處理。當(dāng)請(qǐng)求出現(xiàn)錯(cuò)誤時(shí),通常不應(yīng)該將錯(cuò)誤的Promise存儲(chǔ)到緩存中,因?yàn)檫@可能導(dǎo)致后續(xù)所有對(duì)該數(shù)據(jù)的請(qǐng)求都會(huì)立即返回錯(cuò)誤。相反,可以選擇在錯(cuò)誤處理邏輯中移除緩存項(xiàng),或者采取其他的恢復(fù)機(jī)制。
緩存策略的考慮
實(shí)現(xiàn)緩存時(shí),還需要考慮它的有效性和過時(shí)機(jī)制。只有當(dāng)數(shù)據(jù)不頻繁變化或者對(duì)即時(shí)性要求不高的情況下,緩存才是合理的。尤其是在一些數(shù)據(jù)更新周期較長的場(chǎng)景,例如一些配置數(shù)據(jù)、用戶信息等,使用緩存能帶來顯著的性能提升。
有時(shí)候,需要設(shè)立緩存過期機(jī)制,即數(shù)據(jù)在緩存中存儲(chǔ)一段時(shí)間后失效,之后的請(qǐng)求將強(qiáng)制發(fā)起新的網(wǎng)絡(luò)請(qǐng)求以獲取最新數(shù)據(jù)。緩存過期機(jī)制可以通過定時(shí)器或者請(qǐng)求次數(shù)等方式來實(shí)現(xiàn)。
結(jié)語
合理地使用Promise和緩存可以顯著提升應(yīng)用的性能,減輕服務(wù)器的負(fù)擔(dān),并提供更加流暢的用戶體驗(yàn)。通過在正確的地方引入緩存,可以有效地避免不必要的網(wǎng)絡(luò)請(qǐng)求,加快數(shù)據(jù)的加載速度。在此基礎(chǔ)上,合理設(shè)置緩存失效機(jī)制,能夠確保用戶始終獲取到最新的數(shù)據(jù),避免緩存導(dǎo)致的數(shù)據(jù)過時(shí)問題。
通過上述示例的實(shí)踐,開發(fā)者可以根據(jù)自身應(yīng)用的需要,定制適合自己業(yè)務(wù)場(chǎng)景的網(wǎng)絡(luò)請(qǐng)求緩存方案。這不僅可以提高程序性能,還可以增加程序的魯棒性,優(yōu)化用戶的交互體驗(yàn)。
以上就是詳解JS如何使用Promise緩存網(wǎng)絡(luò)請(qǐng)求的詳細(xì)內(nèi)容,更多關(guān)于JS Promise緩存網(wǎng)絡(luò)請(qǐng)求的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
javascript實(shí)現(xiàn)禁止復(fù)制網(wǎng)頁內(nèi)容
這篇文章主要介紹了javascript實(shí)現(xiàn)禁止復(fù)制網(wǎng)頁內(nèi)容,需要的朋友可以參考下2014-12-12JS中的hasOwnProperty()和isPrototypeOf()屬性實(shí)例詳解
hasOwnProperty()和isPrototypeOf()這兩個(gè)屬性都是Object.prototype所提供:Object.prototype.hasOwnProperty()和Object.prototype.isPropertyOf(),下面給大家介紹這兩個(gè)屬性的方法和使用,一起看下吧2016-08-08js實(shí)現(xiàn)的早期滑動(dòng)門菜單效果代碼
這篇文章主要介紹了js實(shí)現(xiàn)的早期滑動(dòng)門菜單效果代碼,涉及javascript數(shù)組遍歷及通過鼠標(biāo)事件動(dòng)態(tài)改變頁面元素屬性的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-08-08深入理解JavaScript中的尾調(diào)用(Tail Call)
尾調(diào)用(Tail Call)是函數(shù)式編程的一個(gè)重要概念,下面這篇文章主要給大家深入的介紹了關(guān)于JavaScript中尾調(diào)用的相關(guān)資料,文中介紹的非常詳細(xì),相信對(duì)大家具有一定的參考價(jià)值,有需要的朋友們下面來一起看看吧。2017-02-02原生js實(shí)現(xiàn)的觀察者和訂閱者模式簡單示例
這篇文章主要介紹了原生js實(shí)現(xiàn)的觀察者和訂閱者模式,結(jié)合簡單實(shí)例形式分析了js觀察者和訂閱者模式的相關(guān)原理與實(shí)現(xiàn)技巧,需要的朋友可以參考下2020-04-04JavaScript中使用參數(shù)個(gè)數(shù)實(shí)現(xiàn)重載功能
這篇文章主要介紹了JavaScript中使用參數(shù)個(gè)數(shù)實(shí)現(xiàn)重載功能,需要的朋友可以參考下2017-09-09深入理解javascript構(gòu)造函數(shù)和原型對(duì)象
對(duì)象,是javascript中非常重要的一個(gè)梗,是否能透徹的理解它直接關(guān)系到你對(duì)整個(gè)javascript體系的基礎(chǔ)理解,說白了,javascript就是一群對(duì)象在攪。。(嗶?。?。2014-09-09