在開發(fā) web 應(yīng)用程序時,性能是一個重要的話題。為了提高用戶體驗和節(jié)省網(wǎng)絡(luò)資源,我們需要對一些頻繁或重復(fù)的 API 請求進(jìn)行緩存,以減少不必要的服務(wù)器交互。緩存的原理是將第一次請求的數(shù)據(jù)保存在客戶端,之后再次請求時直接從緩存中獲取,而不是向服務(wù)器發(fā)送請求。
緩存的方式有很多種,根據(jù)不同的業(yè)務(wù)場景和需求,我們可以選擇合適的方案來實現(xiàn)緩存功能。本文將介紹前端 API 請求緩存的三種方案,從簡單到復(fù)雜,分別是:
一、數(shù)據(jù)緩存
- 數(shù)據(jù)緩存是最簡單的一種緩存方案,它的思路是將第一次請求的數(shù)據(jù)保存在一個 Map 對象中,以 API 的名稱或參數(shù)作為鍵,以數(shù)據(jù)作為值。之后再次請求時,先從 Map 對象中查找是否有對應(yīng)的數(shù)據(jù),如果有則直接返回,如果沒有則向服務(wù)器發(fā)送請求,并將返回的數(shù)據(jù)保存在 Map 對象中。
- 數(shù)據(jù)緩存的優(yōu)點是實現(xiàn)簡單,適用于一些不需要更新的靜態(tài)數(shù)據(jù)。缺點是無法處理同時多次請求的情況,也無法設(shè)置緩存的有效期,可能會導(dǎo)致數(shù)據(jù)過時或冗余。
示例代碼如下:
// 創(chuàng)建一個 Map 對象用于存儲數(shù)據(jù)
const dataCache = new Map();
// 定義一個獲取商品列表的 API
async function getWares() {
// 以 API 的名稱作為鍵
let key = "wares";
// 從 Map 對象中獲取數(shù)據(jù)
let data = dataCache.getkey;
if (!data) {
// 如果沒有數(shù)據(jù),向服務(wù)器發(fā)送請求
const res = await request.get("/getWares");
// 對返回的數(shù)據(jù)進(jìn)行一些處理
data = res.data;
// 將數(shù)據(jù)保存在 Map 對象中
dataCache.set(key, data);
}
// 返回數(shù)據(jù)
return data;
}
調(diào)用方式如下:
// 第一次調(diào)用,向服務(wù)器發(fā)送請求,獲取數(shù)據(jù)
getWares().then((data) => {
console.log(data);
});
// 第二次調(diào)用,從 Map 對象中獲取數(shù)據(jù),不再發(fā)送請求
getWares().then((data) => {
console.log(data);
});
二、Promise 緩存
- Promise 緩存是對數(shù)據(jù)緩存的改進(jìn),它的思路是將第一次請求的 Promise 對象保存在一個 Map 對象中,以 API 的名稱或參數(shù)作為鍵,以 Promise 對象作為值。之后再次請求時,先從 Map 對象中查找是否有對應(yīng)的 Promise 對象,如果有則直接返回,如果沒有則向服務(wù)器發(fā)送請求,并將返回的 Promise 對象保存在 Map 對象中。
- Promise 緩存的優(yōu)點是可以處理同時多次請求的情況,避免重復(fù)發(fā)送請求,只有第一次請求會向服務(wù)器發(fā)送請求,之后的請求都會等待第一次請求的結(jié)果。缺點是無法設(shè)置緩存的有效期,可能會導(dǎo)致數(shù)據(jù)過時或冗余。
示例代碼如下:
// 創(chuàng)建一個 Map 對象用于存儲 Promise 對象
const promiseCache = new Map();
// 定義一個獲取商品列表的 API
function getWares() {
// 以 API 的名稱作為鍵
let key = "wares";
// 從 Map 對象中獲取 Promise 對象
let promise = promiseCache.getkey;
// 如果沒有 Promise 對象
if (!promise) {
// 向服務(wù)器發(fā)送請求,并返回一個 Promise 對象
promise = request.get("/getWares").then((res) => {
// 對返回的數(shù)據(jù)進(jìn)行一些處理
return res.data;
}).catch((error) => {
// 如果請求出錯,從 Map 對象中刪除 Promise 對象,避免緩存錯誤的結(jié)果
promiseCache.deletekey;
// 拋出錯誤
return Promise.reject(error);
});
// 將 Promise 對象保存在 Map 對象中
promiseCache.set(key, promise);
}
// 返回 Promise 對象
return promise;
}
調(diào)用方式如下:
// 第一次調(diào)用,向服務(wù)器發(fā)送請求,獲取數(shù)據(jù)
getWares().then((data) => {
console.log(data);
});
// 第二次調(diào)用,從 Map 對象中獲取 Promise 對象,不再發(fā)送請求,等待第一次請求的結(jié)果
getWares().then((data) => {
console.log(data);
});
三、多 Promise 緩存
- 多 Promise 緩存是對 Promise 緩存的擴展,它的思路是將多個 API 請求的 Promise 對象保存在一個 Map 對象中,以 API 的名稱或參數(shù)作為鍵,以 Promise 對象作為值。之后再次請求時,先從 Map 對象中查找是否有對應(yīng)的 Promise 對象,如果有則直接返回,如果沒有則向服務(wù)器發(fā)送請求,并將返回的 Promise 對象保存在 Map 對象中。最后,使用 Promise.all 方法將多個 Promise 對象合并為一個 Promise 對象,統(tǒng)一返回結(jié)果。
- 多 Promise 緩存的優(yōu)點是可以同時獲取多個 API 請求的數(shù)據(jù),提高效率,只有第一次請求會向服務(wù)器發(fā)送請求,之后的請求都會等待第一次請求的結(jié)果。缺點是無法設(shè)置緩存的有效期,可能會導(dǎo)致數(shù)據(jù)過時或冗余。另外,如果其中一個 API 請求出錯,會導(dǎo)致整個 Promise 對象被拒絕,無法獲取其他 API 請求的數(shù)據(jù)。
示例代碼如下:
// 定義一個對象,存儲 API 的名稱和對應(yīng)的請求地址
const querys = {
wares: "/getWares",
skus: "/getSku",
};
// 創(chuàng)建一個 Map 對象用于存儲 Promise 對象
const promiseCache = new Map();
// 定義一個函數(shù),用于同時獲取多個 API 請求的數(shù)據(jù)
async function queryAll(queryApiName) {
// 判斷傳入的參數(shù)是否是數(shù)組
const queryIsArray = Array.isArray(queryApiName);
// 統(tǒng)一處理參數(shù),無論是字符串還是數(shù)組,都視為數(shù)組
const apis = queryIsArray ? queryApiName : [queryApiName];
// 創(chuàng)建一個數(shù)組,用于存儲所有的 Promise 對象
const promiseApi = [];
// 遍歷參數(shù)數(shù)組,對每個 API 進(jìn)行處理
apis.forEach((api) => {
// 從 Map 對象中獲取 Promise 對象
let promise = promiseCache.get(api);
// 如果沒有 Promise 對象
if (!promise) {
// 向服務(wù)器發(fā)送請求,并返回一個 Promise 對象
promise = request.get(querys[api]).then((res) => {
// 對返回的數(shù)據(jù)進(jìn)行一些處理
return res.data;
}).catch((error) => {
// 如果請求出錯,從 Map 對象中刪除 Promise 對象,避免緩存錯誤的結(jié)果
promiseCache.delete(api);
// 拋出錯誤
return Promise.reject(error);
});
// 將 Promise 對象保存在 Map 對象中
promiseCache.set(api, promise);
}
// 將 Promise 對象添加到數(shù)組中
promiseApi.push(promise);
});
// 使用 Promise.all 方法將多個 Promise 對象合并為一個 Promise 對象
return Promise.all(promiseApi).then((res) => {
// 根據(jù)傳入的參數(shù)是字符串還是數(shù)組來返回數(shù)據(jù),因為本身都是數(shù)組操作
// 如果傳入的是字符串,則需要取出第一個元素
return queryIsArray ? res : res[0];
});
}
調(diào)用方式如下:
// 第一次調(diào)用,向服務(wù)器發(fā)送請求,獲取數(shù)據(jù)
queryAll("wares").then((data) => {
console.log(data);
});
// 第二次調(diào)用,從 Map 對象中獲取 Promise 對象,不再發(fā)送請求,等待第一次請求的結(jié)果
queryAll(["wares", "skus"]).then((data) => {
console.log(data);
});
總結(jié)
通過實施API請求緩存,我們可以顯著提高前端應(yīng)用程序的性能和用戶體驗。選擇合適的緩存方案取決于應(yīng)用程序的需求和特點。在實際開發(fā)中,我們可以根據(jù)數(shù)據(jù)的變化頻率、數(shù)據(jù)的重要性、存儲空間的限制等因素來選擇適當(dāng)?shù)姆桨浮=Y(jié)合合適的緩存方案,我們可以有效地減少網(wǎng)絡(luò)請求,提高應(yīng)用程序的響應(yīng)速度,并降低服務(wù)器負(fù)載。同時,需要注意緩存的更新策略,以確保數(shù)據(jù)的準(zhǔn)確性和實時性。
如果你對前端工程師職業(yè)和編程技術(shù)感興趣,不妨訪問編程獅官網(wǎng)(http://o2fo.com/)。編程獅官網(wǎng)提供了大量的技術(shù)文章、編程教程和資源,涵蓋了前端工程師、編程、職業(yè)規(guī)劃等多個領(lǐng)域的知識。無論你是初學(xué)者還是有經(jīng)驗的開發(fā)者,編程獅官網(wǎng)都為你提供了有用的信息和資源,助你在編程領(lǐng)域取得成功。不要錯過這個寶貴的學(xué)習(xí)機會!