Caching Strategies and Implementation
Caching is a critical technique for improving network request performance. Effective caching reduces the frequency of server requests, lowers latency, and enhances user experience.
In-Memory Caching
In-memory caching is straightforward and suitable for data that doesn’t require long-term storage. You can use JavaScript’s Map or a custom cache class.
const cache = new Map();
function fetchFromCacheOrServer(url) {
if (cache.has(url)) {
return Promise.resolve(cache.get(url));
}
return axios.get(url)
.then(response => {
cache.set(url, response.data);
return response.data;
});
}Local Storage Caching
For data requiring persistent storage, use localStorage or sessionStorage.
function fetchFromLocalStorageOrServer(url) {
const cachedData = localStorage.getItem(url);
if (cachedData) {
return Promise.resolve(JSON.parse(cachedData));
}
return axios.get(url)
.then(response => {
localStorage.setItem(url, JSON.stringify(response.data));
return response.data;
});
}HTTP Caching
Leverage HTTP protocol caching mechanisms like ETag and Last-Modified to let browsers handle caching automatically.
axios.get('/data', {
headers: {
'If-None-Match': localStorage.getItem('etag') || ''
}
})
.then(response => {
if (response.status === 304) {
return JSON.parse(localStorage.getItem('data'));
}
localStorage.setItem('etag', response.headers.etag);
localStorage.setItem('data', JSON.stringify(response.data));
return response.data;
});Reducing Network Request Frequency (Data Merging, Prefetching)
Data Merging: Batch Requests and Combined Responses
Data merging consolidates multiple independent network requests into a single request, reducing server interactions.
Batch Requests
Use axios.all to issue multiple requests concurrently and handle results when all complete.
const axios = require('axios');
const urls = ['/data1', '/data2', '/data3'];
const requests = urls.map(url => axios.get(url));
axios.all(requests)
.then(axios.spread((res1, res2, res3) => {
// Process multiple responses
}))
.catch(errors => {
// Handle errors
});This still sends separate requests. For true merging, use a more advanced strategy.
Merged Requests
Pack multiple requests into a single request sent to the server, which processes and returns combined data.
const axios = require('axios');
const urls = ['/data1', '/data2', '/data3'];
const payload = urls.reduce((acc, url) => ({ ...acc, [url]: null }), {});
axios.post('/batch', payload)
.then(response => {
// Process combined response
})
.catch(error => {
// Handle errors
});The server must support this batch endpoint and return corresponding data, requiring custom backend logic.
Prefetching: Preloading Data
Prefetching loads data before it’s needed, reducing user wait times and improving experience.
Link Prefetching
HTML5’s <link rel="prefetch"> tag enables browsers to preload resources during idle time.
<link rel="prefetch" href="/next-page">This is limited to static resources. For dynamic data, use JavaScript.
Dynamic Data Prefetching
Use Axios to prefetch dynamic data during page load or before user actions.
window.addEventListener('DOMContentLoaded', () => {
axios.get('/next-page-data')
.then(response => {
// Store prefetched data
});
});Adjust prefetch timing and strategy to avoid unnecessary network traffic and resource waste.
Code Analysis
Consider an application needing user info, order lists, and product details from a server. We’ll optimize using data merging and prefetching.
Data Merging
Create a batch request function.
function batchRequests(urls) {
const payload = urls.reduce((acc, url) => ({ ...acc, [url]: null }), {});
return axios.post('/batch', payload);
}
const urls = ['/user-info', '/order-list', '/product-details'];
batchRequests(urls)
.then(response => {
// Process combined response
})
.catch(error => {
// Handle errors
});The server must implement the /batch endpoint to parse URLs and return data.
Prefetching
Implement prefetching during page load.
window.addEventListener('DOMContentLoaded', () => {
axios.get('/user-info')
.then(response => {
// Store prefetched data
});
});Store prefetched data in memory or persistent storage like localStorage for later use.
Using Keep-Alive for Persistent Connections
Keep-Alive is a network protocol mechanism that maintains an HTTP connection between client and server instead of closing it after each request. This reduces connection setup time, improving efficiency for multiple requests.
While Axios doesn’t directly control TCP-level Keep-Alive, you can achieve similar effects through:
- Custom HTTP Agent in Node.js
- Proxy server configuration
Custom HTTP Agent in Node.js
In Node.js, use http.Agent or https.Agent to create a custom agent with Keep-Alive enabled, then pass it to Axios.
const axios = require('axios');
const http = require('http');
const agent = new http.Agent({ keepAlive: true });
axios({
url: 'http://example.com',
method: 'get',
httpAgent: agent
})
.then(response => {
console.log(response.data);
})
.catch(error => {
console.error(error);
});Here, agent is an http.Agent instance with Keep-Alive enabled, ensuring persistent connections.
Proxy Server Configuration
If your app uses a proxy server, configure it for Keep-Alive. Web servers like Nginx and Apache support this.
Nginx Example Configuration:
http {
#...
keepalive_timeout 65;
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
}In this Nginx config, keepalive_timeout sets the Keep-Alive timeout, and proxy_pass should point to your backend service.
Notes
- Keep-Alive improves efficiency but may increase server resource usage by maintaining more connections. Adjust timeout and max connections in high-concurrency environments.
- Network devices may close idle connections despite Keep-Alive settings. Sending periodic heartbeat packets can keep connections active.



