乐闻世界logo
搜索文章和话题

What performance optimization techniques are there when using axios? How to reduce unnecessary network requests?

3月6日 23:02

When using axios for HTTP requests, performance can be optimized in various ways to reduce unnecessary network overhead and improve user experience.

1. Request Caching

Memory Cache

javascript
class AxiosCache { constructor() { this.cache = new Map(); this.ttl = 5 * 60 * 1000; // 5 minute cache } generateKey(config) { return `${config.method}-${config.url}-${JSON.stringify(config.params)}`; } get(config) { const key = this.generateKey(config); const cached = this.cache.get(key); if (cached && Date.now() - cached.timestamp < this.ttl) { return cached.data; } this.cache.delete(key); return null; } set(config, data) { const key = this.generateKey(config); this.cache.set(key, { data, timestamp: Date.now() }); } clear() { this.cache.clear(); } } const cache = new AxiosCache(); // Axios instance with cache const cachedApi = axios.create(); cachedApi.interceptors.request.use(config => { // Check cache const cached = cache.get(config); if (cached) { // Return cached data, cancel request config.adapter = () => Promise.resolve({ data: cached, status: 200, statusText: 'OK', headers: {}, config }); } return config; }); cachedApi.interceptors.response.use(response => { // Cache response data if (response.config.method === 'get') { cache.set(response.config, response.data); } return response; });

Using Cache API (Service Worker)

javascript
// Cache requests in Service Worker self.addEventListener('fetch', event => { if (event.request.url.includes('/api/')) { event.respondWith( caches.match(event.request).then(response => { if (response) { return response; } return fetch(event.request).then(response => { const clone = response.clone(); caches.open('api-cache').then(cache => { cache.put(event.request, clone); }); return response; }); }) ); } });

2. Request Deduplication (Debounce)

javascript
class RequestDeduper { constructor() { this.pendingRequests = new Map(); } generateKey(config) { return `${config.method}-${config.url}-${JSON.stringify(config.params)}-${JSON.stringify(config.data)}`; } async request(config) { const key = this.generateKey(config); // If there's an ongoing identical request, return that Promise if (this.pendingRequests.has(key)) { return this.pendingRequests.get(key); } // Create new request const promise = axios(config).finally(() => { this.pendingRequests.delete(key); }); this.pendingRequests.set(key, promise); return promise; } } const deduper = new RequestDeduper(); // Usage const fetchUser = (id) => deduper.request({ method: 'GET', url: `/api/users/${id}` }); // Call multiple times simultaneously, only one request will be sent fetchUser(1); fetchUser(1); fetchUser(1); // Three calls, one request

3. Request Batching

javascript
class RequestBatcher { constructor() { this.batch = []; this.timeout = null; this.delay = 50; // Merge requests within 50ms } addRequest(request) { return new Promise((resolve, reject) => { this.batch.push({ request, resolve, reject }); clearTimeout(this.timeout); this.timeout = setTimeout(() => this.flush(), this.delay); }); } async flush() { if (this.batch.length === 0) return; const currentBatch = this.batch; this.batch = []; // Merge requests const ids = currentBatch.map(item => item.request.id); try { const response = await axios.post('/api/batch', { ids }); // Distribute results currentBatch.forEach((item, index) => { item.resolve(response.data[index]); }); } catch (error) { currentBatch.forEach(item => { item.reject(error); }); } } }

4. Lazy Loading and Pagination

javascript
// Virtual scroll + pagination loading class VirtualListLoader { constructor(api, pageSize = 20) { this.api = api; this.pageSize = pageSize; this.cache = new Map(); this.loadingPages = new Set(); } async loadPage(page) { // Check cache if (this.cache.has(page)) { return this.cache.get(page); } // Prevent duplicate loading if (this.loadingPages.has(page)) { return new Promise(resolve => { const check = setInterval(() => { if (this.cache.has(page)) { clearInterval(check); resolve(this.cache.get(page)); } }, 100); }); } this.loadingPages.add(page); try { const response = await this.api.get('/api/items', { params: { page, pageSize: this.pageSize } }); this.cache.set(page, response.data); return response.data; } finally { this.loadingPages.delete(page); } } }

5. Request Priority Management

javascript
class PriorityRequestQueue { constructor() { this.queue = []; this.maxConcurrent = 6; // Browser max concurrent requests this.running = 0; } add(config, priority = 0) { return new Promise((resolve, reject) => { this.queue.push({ config, priority, resolve, reject }); this.queue.sort((a, b) => b.priority - a.priority); this.process(); }); } async process() { if (this.running >= this.maxConcurrent || this.queue.length === 0) { return; } this.running++; const { config, resolve, reject } = this.queue.shift(); try { const response = await axios(config); resolve(response); } catch (error) { reject(error); } finally { this.running--; this.process(); } } } // Usage const queue = new PriorityRequestQueue(); // High priority request queue.add({ url: '/api/critical-data' }, 10); // Low priority request queue.add({ url: '/api/background-data' }, 1);

6. Compression and Request Minimization

javascript
// Request data compression const compressRequest = (data) => { // Remove undefined and null values const cleaned = JSON.parse(JSON.stringify(data)); return cleaned; }; // Field minimization const minimizeFields = (fields) => { // Only request needed fields return fields.join(','); }; axios.get('/api/users', { params: { fields: minimizeFields(['id', 'name', 'avatar']), include: minimizeFields(['posts', 'comments']) } });

7. Using HTTP/2 Server Push

javascript
// Server configuration for HTTP/2 Push // Add Link header in response // Link: </api/related-data>; rel=preload; as=fetch // Client preloading const preloadResources = () => { const links = document.querySelectorAll('link[rel=preload][as=fetch]'); links.forEach(link => { axios.get(link.href, { headers: { 'Purpose': 'prefetch' } }); }); };

8. Connection Reuse and Keep-Alive

javascript
// Use same axios instance to reuse connections const api = axios.create({ baseURL: 'https://api.example.com', // Enable keep-alive (in Node.js) httpAgent: new http.Agent({ keepAlive: true }), httpsAgent: new https.Agent({ keepAlive: true }) }); // Browser automatically reuses connections

9. Request Timeout Optimization

javascript
// Dynamically adjust timeout based on network conditions const getTimeout = () => { const connection = navigator.connection; if (connection) { switch (connection.effectiveType) { case '4g': return 10000; case '3g': return 20000; case '2g': return 30000; default: return 15000; } } return 10000; }; axios.get('/api/data', { timeout: getTimeout() });

10. Error Retry Strategy

javascript
axios.interceptors.response.use(null, async (error) => { const { config } = error; if (!config || !config.retry) { return Promise.reject(error); } config.retryCount = config.retryCount || 0; if (config.retryCount >= config.retry) { return Promise.reject(error); } config.retryCount += 1; // Exponential backoff const backoff = Math.pow(2, config.retryCount) * 1000; await new Promise(resolve => setTimeout(resolve, backoff)); return axios(config); }); // Usage axios.get('/api/data', { retry: 3, retryDelay: 1000 });

11. Offline-First Strategy

javascript
// Use IndexedDB for caching const offlineFirstRequest = async (config) => { try { // Try network request first const response = await axios(config); // Cache to IndexedDB await saveToIndexedDB(config, response.data); return response; } catch (error) { // Network failed, try to read from cache const cached = await getFromIndexedDB(config); if (cached) { return { data: cached, fromCache: true }; } throw error; } };

12. Monitoring and Analytics

javascript
// Performance monitoring interceptor axios.interceptors.request.use(config => { config.metadata = { startTime: Date.now() }; return config; }); axios.interceptors.response.use(response => { const duration = Date.now() - response.config.metadata.startTime; // Report performance data analytics.track('api_request', { url: response.config.url, method: response.config.method, duration, status: response.status, size: JSON.stringify(response.data).length }); // Slow request warning if (duration > 3000) { console.warn(`Slow request: ${response.config.url} took ${duration}ms`); } return response; });

Best Practices Summary

Optimization StrategyApplicable ScenarioExpected Effect
Request CachingInfrequently changing dataReduce 50-90% requests
Request DeduplicationRapid consecutive triggersReduce duplicate requests
Request BatchingBatch operationsReduce request count
Pagination LoadingLong listsReduce initial load time
Priority QueueCritical/non-critical requestsImprove critical request response
Data CompressionLarge data transfersReduce transfer volume
Connection ReuseFrequent requestsReduce connection overhead
Smart TimeoutUnstable networksImprove user experience
Error RetryTemporary failuresImprove success rate
Offline-FirstWeak network environmentsImprove availability

标签:JavaScript前端Axios