AJAX请求过多会导致服务器压力大、网络负载高、用户体验差。以下是四种常见解决方案:
将多个小请求合并为单个大请求,减少请求次数:
// 示例:批量获取用户信息
async function batchGetUserInfo(userIds) {
// 将多个ID合并为一次请求
const response = await fetch('/api/users/batch', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ ids: userIds })
});
return response.json();
}
// 或者使用请求队列
class RequestBatcher {
constructor(batchSize = 10, delay = 100) {
this.queue = [];
this.batchSize = batchSize;
this.delay = delay;
this.timeout = null;
}
addRequest(request) {
this.queue.push(request);
if (this.queue.length >= this.batchSize) {
this.executeBatch();
} else if (!this.timeout) {
this.timeout = setTimeout(() => this.executeBatch(), this.delay);
}
}
async executeBatch() {
if (this.timeout) {
clearTimeout(this.timeout);
this.timeout = null;
}
if (this.queue.length === 0) return;
const batch = this.queue.splice(0, this.batchSize);
// 执行批量请求
await this.sendBatchRequest(batch);
}
}
控制请求频率,避免过于频繁的请求:
// 防抖:等待用户停止操作后再请求
function debounce(func, wait) {
let timeout;
return function(...args) {
clearTimeout(timeout);
timeout = setTimeout(() => func.apply(this, args), wait);
};
}
// 节流:固定时间间隔内只执行一次
function throttle(func, limit) {
let inThrottle;
return function(...args) {
if (!inThrottle) {
func.apply(this, args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
};
}
// 使用示例
const searchInput = document.getElementById('search');
const searchHandler = debounce(async (event) => {
const query = event.target.value;
if (query.length > 2) {
const results = await fetch(`/api/search?q=${query}`);
// 更新UI
}
}, 300);
searchInput.addEventListener('input', searchHandler);
实现客户端缓存,减少重复请求:
class RequestCache {
constructor(defaultTTL = 300000) { // 默认5分钟
this.cache = new Map();
this.defaultTTL = defaultTTL;
}
async get(url, options = {}) {
const cacheKey = this.createKey(url, options);
const cached = this.cache.get(cacheKey);
if (cached && Date.now() < cached.expiry) {
return cached.data;
}
// 缓存未命中或已过期
const response = await fetch(url, options);
const data = await response.json();
this.set(cacheKey, data, options.ttl || this.defaultTTL);
return data;
}
set(key, data, ttl) {
this.cache.set(key, {
data,
expiry: Date.now() + ttl
});
}
createKey(url, options) {
return JSON.stringify({ url, options });
}
// 可选:定时清理过期缓存
startCleanup(interval = 60000) {
setInterval(() => {
const now = Date.now();
for (const [key, value] of this.cache.entries()) {
if (now >= value.expiry) {
this.cache.delete(key);
}
}
}, interval);
}
}
// 使用缓存
const cache = new RequestCache();
async function getProductInfo(productId) {
return cache.get(`/api/products/${productId}`);
}
对于实时性要求高的场景,使用长连接替代频繁的AJAX轮询:
// WebSocket示例
class RealTimeService {
constructor(url) {
this.ws = new WebSocket(url);
this.subscribers = new Map();
this.setupWebSocket();
}
setupWebSocket() {
this.ws.onmessage = (event) => {
const data = JSON.parse(event.data);
const { type, payload } = data;
// 通知对应类型的订阅者
if (this.subscribers.has(type)) {
this.subscribers.get(type).forEach(callback => callback(payload));
}
};
this.ws.onopen = () => {
console.log('WebSocket连接已建立');
};
}
subscribe(type, callback) {
if (!this.subscribers.has(type)) {
this.subscribers.set(type, []);
}
this.subscribers.get(type).push(callback);
}
send(type, data) {
this.ws.send(JSON.stringify({ type, data }));
}
}
// Server-Sent Events (SSE) 示例
class SSEClient {
constructor(url) {
this.eventSource = new EventSource(url);
this.callbacks = new Map();
this.eventSource.onmessage = (event) => {
const data = JSON.parse(event.data);
this.handleEvent(data);
};
}
on(eventType, callback) {
this.eventSource.addEventListener(eventType, (event) => {
callback(JSON.parse(event.data));
});
}
}
实际项目中通常组合使用多种方案:
class OptimizedAPIClient {
constructor() {
this.cache = new RequestCache();
this.pendingRequests = new Map();
}
async request(url, options = {}) {
const {
useCache = true,
debounceTime = 0,
batchKey = null
} = options;
// 1. 检查缓存
if (useCache) {
const cached = this.cache.get(url);
if (cached) return cached;
}
// 2. 防抖处理
if (debounceTime > 0) {
return this.debouncedRequest(url, options, debounceTime);
}
// 3. 批处理
if (batchKey) {
return this.batchRequest(url, options, batchKey);
}
// 普通请求
return this.fetchWithTimeout(url, options);
}
async batchRequest(url, options, batchKey) {
// 实现批处理逻辑
}
debouncedRequest(url, options, wait) {
// 实现防抖逻辑
}
async fetchWithTimeout(url, options) {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 10000);
try {
const response = await fetch(url, {
...options,
signal: controller.signal
});
clearTimeout(timeoutId);
return response.json();
} catch (error) {
clearTimeout(timeoutId);
throw error;
}
}
}
| 场景 | 推荐方案 | 理由 |
|---|---|---|
| 搜索框实时搜索 | 防抖 + 缓存 | 减少无效请求,快速响应 |
| 数据仪表盘 | 批处理 + WebSocket | 减少连接数,实时更新 |
| 电商商品列表 | 缓存 + 节流 | 快速加载,避免重复请求 |
| 聊天应用 | WebSocket | 实时双向通信 |
根据具体业务场景,选择合适的组合方案,可以有效优化AJAX请求过多的问题。