上一篇
想象一下,你正在开发一个电商平台的首页,每次用户刷新页面,都需要从数据库加载商品推荐、促销活动、用户个性化设置等数据,随着流量增长,数据库开始不堪重负,页面加载时间从1秒逐渐恶化到3-4秒,这时候,技术团队决定引入Redis作为缓存层,但问题来了:前端如何高效地从Redis获取这些数据?
首先需要明确的是,前端通常不会直接连接Redis,Redis是内存数据库,设计上是为后端服务提供高速缓存能力,前端与Redis的交互需要通过后端API作为桥梁,大致流程是这样的:
这是最常见的方式,前端像调用普通API一样获取数据,完全不用关心后端是否用了Redis。
async function fetchProductRecommendations() { try { const response = await fetch('/api/recommendations'); if (!response.ok) { throw new Error('Network response was not ok'); } const data = await response.json(); console.log('推荐商品:', data); return data; } catch (error) { console.error('获取推荐失败:', error); // 可以在这里添加降级处理,比如返回本地缓存或默认数据 return getLocalFallbackData(); } }
后端对应的Node.js代码示例:
import redis from 'redis'; const client = redis.createClient(); const cacheKey = 'product:recommendations'; app.get('/api/recommendations', async (req, res) => { try { // 先尝试从Redis获取 const cachedData = await client.get(cacheKey); if (cachedData) { return res.json(JSON.parse(cachedData)); } // Redis中没有,从数据库获取 const dbData = await db.query('SELECT * FROM products WHERE recommended = true'); // 存入Redis,设置1小时过期 await client.setex(cacheKey, 3600, JSON.stringify(dbData)); res.json(dbData); } catch (err) { res.status(500).json({ error: '服务器错误' }); } });
对于需要实时更新的数据,可以考虑WebSocket方案:
const socket = new WebSocket('wss://your-api.com/realtime'); socket.onmessage = (event) => { const data = JSON.parse(event.data); if (data.type === 'recommendations') { updateUI(data.payload); } }; // 初始化时请求一次数据 socket.onopen = () => { socket.send(JSON.stringify({ action: 'subscribe', channel: 'recommendations' })); };
后端需要维护WebSocket连接并在Redis数据变更时推送:
// Node.js + WebSocket示例 wss.on('connection', (ws) => { // 订阅Redis频道 const subscriber = redis.createClient(); subscriber.subscribe('recommendations_update'); subscriber.on('message', (channel, message) => { if (channel === 'recommendations_update') { ws.send(message); } }); // 客户端断开连接时取消订阅 ws.on('close', () => { subscriber.unsubscribe(); }); });
SSE是另一种实时通信方案,比WebSocket更简单:
const eventSource = new EventSource('/api/recommendations/stream'); eventSource.onmessage = (event) => { const data = JSON.parse(event.data); updateRecommendations(data); }; eventSource.onerror = () => { console.log('SSE连接错误,尝试重新连接...'); // EventSource会自动重连 };
后端实现:
app.get('/api/recommendations/stream', (req, res) => { res.setHeader('Content-Type', 'text/event-stream'); res.setHeader('Cache-Control', 'no-cache'); res.setHeader('Connection', 'keep-alive'); // 初始发送一次数据 sendCurrentData(); // 订阅Redis变更 const subscriber = redis.createClient(); subscriber.subscribe('recommendations_update'); subscriber.on('message', (channel, message) => { if (channel === 'recommendations_update') { res.write(`data: ${message}\n\n`); } }); // 客户端断开时清理 req.on('close', () => { subscriber.unsubscribe(); }); async function sendCurrentData() { const data = await getRecommendations(); res.write(`data: ${JSON.stringify(data)}\n\n`); } });
批量请求:合并多个小请求为一个批量请求
async function fetchMultipleResources() { const [userData, recommendations, promotions] = await Promise.all([ fetch('/api/user'), fetch('/api/recommendations'), fetch('/api/promotions') ]); // 处理数据... }
客户端缓存:使用localStorage或sessionStorage暂存数据
async function getCachedData(key, fetchFunc) { const cached = localStorage.getItem(key); if (cached) { return JSON.parse(cached); } const freshData = await fetchFunc(); localStorage.setItem(key, JSON.stringify(freshData)); return freshData; }
过期策略:为客户端缓存设置合理的过期时间
function isCacheValid(key, maxAge) { const entry = localStorage.getItem(key + '_meta'); if (!entry) return false; const { timestamp } = JSON.parse(entry); return Date.now() - timestamp < maxAge; }
请求去重:避免短时间内重复请求相同资源
const pendingRequests = {}; async function dedupedFetch(url) { if (pendingRequests[url]) { return pendingRequests[url]; } const promise = fetch(url).finally(() => { delete pendingRequests[url]; }); pendingRequests[url] = promise; return promise; }
即使有了Redis缓存,网络请求仍可能失败,良好的错误处理至关重要:
async function getDataWithFallback() { try { const response = await fetch('/api/data'); if (!response.ok) throw new Error('API错误'); return await response.json(); } catch (error) { console.warn('使用备用数据:', error); // 1. 尝试从localStorage获取缓存 const cached = localStorage.getItem('fallbackData'); if (cached) return JSON.parse(cached); // 2. 使用硬编码的默认数据 return getDefaultData(); // 3. 根据业务需求,可以返回空数据或显示错误界面 } }
假设我们有一个电商首页需要展示:
优化后的数据流:
页面加载时发起单个组合请求:
async function loadHomePageData() { const response = await fetch('/api/home?userId=123'); const { recommendations, promotions, history, inventory } = await response.json(); renderRecommendations(recommendations); renderPromotions(promotions); // ...其他渲染逻辑 }
后端实现:
app.get('/api/home', async (req, res) => { const userId = req.query.userId; const cacheKey = `home:${userId}`; try { const cached = await redis.get(cacheKey); if (cached) { return res.json(JSON.parse(cached)); } const [recs, promos, hist, inv] = await Promise.all([ getRecommendations(userId), getPromotions(), getHistory(userId), getInventoryStatus() ]); const responseData = { recommendations: recs, promotions: promos, history: hist, inventory: inv }; // 缓存5分钟 await redis.setex(cacheKey, 300, JSON.stringify(responseData)); res.json(responseData); } catch (err) { res.status(500).json({ error: err.message }); } });
实时库存更新通过SSE推送:
const inventoryUpdates = new EventSource('/api/inventory/updates'); inventoryUpdates.onmessage = (event) => { const update = JSON.parse(event.data); updateInventoryDisplay(update.productId, update.stock); };
通过Redis缓存结合前端异步请求,可以显著提升应用性能,关键点包括:
Redis是性能优化的利器,但不要过度依赖,合理的缓存策略加上优雅的前端实现,才能打造出真正流畅的用户体验。
本文由 姓白萱 于2025-08-02发表在【云服务器提供商】,文中图片由(姓白萱)上传,本平台仅提供信息存储服务;作者观点、意见不代表本站立场,如有侵权,请联系我们删除;若有图片侵权,请您准备原始证明材料和公证书后联系我方删除!
本文链接:https://vps.7tqx.com/wenda/511855.html
发表评论