网络请求性能优化策略
- 请求防抖与节流
- 防抖:在短时间内多次触发同一请求时,防抖策略会等待一定时间(例如200ms),如果在这个等待时间内没有再次触发,则执行请求。如果再次触发,则重新计算等待时间。这适用于搜索框输入等场景,用户输入过程中会频繁触发查询请求,但我们希望在用户停止输入后再发起请求,以减少不必要的请求。
- 节流:设定一个固定的时间间隔(例如500ms),在这个时间间隔内,无论触发多少次请求,只执行一次。这对于一些高频操作(如滚动加载更多商品)很有用,可以避免过于频繁的请求。
- 代码示例(Vue中使用lodash的防抖和节流):
<template>
<div>
<input v-model="searchText" @input="debouncedSearch">
</div>
</template>
<script>
import {debounce} from 'lodash';
export default {
data() {
return {
searchText: '',
searchResults: []
};
},
methods: {
async search() {
// 实际的搜索请求逻辑
const response = await fetch(`/api/search?query=${this.searchText}`);
this.searchResults = await response.json();
},
debouncedSearch: debounce(function() {
this.search();
}, 200)
}
};
</script>
- 缓存策略
- 强缓存:利用HTTP的缓存头(如
Cache - Control
和Expires
),对于不经常变化的数据(如商品分类数据),浏览器在缓存有效期内直接从本地缓存加载数据,而不向服务器发送请求。
- 协商缓存:对于可能变化的数据(如商品价格),使用
Last - Modified
和ETag
等头信息。浏览器先发送带有If - Modified - Since
(值为上次获取数据的Last - Modified
值)或If - None - Match
(值为上次获取数据的ETag
值)的请求,服务器根据这些头信息判断数据是否有更新。如果没有更新,返回304状态码,浏览器从本地缓存加载数据;如果有更新,返回新的数据。
- 代码示例(设置缓存头在Node.js服务器端):
const express = require('express');
const app = express();
app.get('/api/categories', (req, res) => {
// 设置强缓存,有效期1小时
res.set('Cache - Control','max - age = 3600');
// 返回商品分类数据
res.json({categories: ['Electronics', 'Clothing', 'Food']});
});
app.get('/api/products/:id', (req, res) => {
const product = getProductById(req.params.id);
// 设置协商缓存
res.set('ETag', product.etag);
if (req.headers['if - none - match'] === product.etag) {
res.status(304).send();
} else {
res.json(product);
}
});
function getProductById(id) {
// 实际的获取商品逻辑
return {id: id, name: 'Sample Product', etag: '123456'};
}
const port = 3000;
app.listen(port, () => {
console.log(`Server running on port ${port}`);
});
- 使用HTTP/2
- HTTP/2具有多路复用、头部压缩等特性,可以显著提高网络性能。多路复用允许在同一个连接上同时发送多个请求和响应,避免了HTTP/1.1中的队头阻塞问题。头部压缩减少了请求和响应头部的大小,从而加快数据传输。
- 部署:在服务器端配置支持HTTP/2。例如,在Nginx服务器中,可以通过以下配置启用HTTP/2:
server {
listen 443 ssl http2;
server_name your_domain.com;
ssl_certificate /path/to/your_certificate;
ssl_certificate_key /path/to/your_private_key;
location / {
proxy_pass http://your_backend_server;
}
}
请求合并策略
- 按模块合并
- 对于同一模块内的多个请求,如果这些请求可以合并成一个请求,就进行合并。例如,在商品列表展示模块中,可能需要获取商品基本信息、商品评论数量、商品销量等数据。可以设计一个接口,一次性返回这些数据,而不是分别发起多个请求。
- 代码示例(假设使用Axios进行HTTP请求):
import axios from 'axios';
// 合并请求
async function getProductDetails(productId) {
const response = await axios.get(`/api/products/${productId}/details`, {
params: {
include: 'comments_count,sales_count'
}
});
return response.data;
}
- 依赖关系处理
- 串行处理:当请求之间存在严格的依赖关系时,采用串行处理。例如,在用户订单查询模块中,可能需要先获取用户的登录信息,然后根据登录信息查询用户的订单。这种情况下,先发起获取登录信息的请求,在得到响应后再发起查询订单的请求。
- 代码示例:
async function getOrders() {
const loginResponse = await axios.get('/api/user/login');
const userId = loginResponse.data.userId;
const ordersResponse = await axios.get(`/api/orders?userId=${userId}`);
return ordersResponse.data;
}
- 并行处理:当请求之间没有依赖关系时,可以并行发起请求,以提高效率。例如,在购物车操作模块中,同时获取购物车商品列表和促销活动信息,可以并行发起这两个请求。
- 代码示例:
async function getCartAndPromotions() {
const [cartResponse, promotionsResponse] = await Promise.all([
axios.get('/api/cart'),
axios.get('/api/promotions')
]);
return {cart: cartResponse.data, promotions: promotionsResponse.data};
}
- 优先级处理
- 可以根据业务场景为不同类型的请求设置优先级。例如,对于购物车结算请求,优先级应该高于商品图片加载请求。在实现上,可以维护一个请求队列,按照优先级顺序处理请求。
- 代码示例(简单的请求队列实现):
class RequestQueue {
constructor() {
this.queue = [];
}
addRequest(request, priority) {
this.queue.push({request, priority});
this.queue.sort((a, b) => b.priority - a.priority);
}
async processQueue() {
while (this.queue.length > 0) {
const {request} = this.queue.shift();
await request();
}
}
}
// 使用示例
const queue = new RequestQueue();
queue.addRequest(() => axios.post('/api/checkout'), 10); // 结算请求,优先级10
queue.addRequest(() => axios.get('/api/product/image'), 5); // 商品图片请求,优先级5
queue.processQueue();
根据业务场景动态调整优化策略
- 用户网络状况
- 使用
navigator.connection
API(在支持的浏览器中)来检测用户的网络类型(如wifi
、cellular
)和网络质量(如effectiveType
)。对于较差的网络状况(如2g
网络),可以适当增加缓存的使用,减少请求频率,或者降低图片质量等资源的请求。
- 代码示例:
if ('connection' in navigator) {
const connection = navigator.connection;
connection.addEventListener('change', () => {
if (connection.effectiveType === '2g') {
// 增加缓存使用,减少请求
// 例如,延长商品图片缓存时间
// 或者降低图片请求的分辨率
}
});
}
- 业务流程阶段
- 在不同的业务流程阶段,采用不同的优化策略。例如,在购物车结算阶段,确保结算请求的准确性和及时性,优先处理结算相关请求,并且对结算请求采用更高的优先级和更严格的请求验证。而在用户浏览商品阶段,可以更多地利用缓存和异步加载策略。
- 代码示例(根据业务流程设置请求优先级):
// 假设处于结算流程
const isCheckout = true;
const queue = new RequestQueue();
if (isCheckout) {
queue.addRequest(() => axios.post('/api/checkout'), 10);
queue.addRequest(() => axios.get('/api/cart'), 5);
} else {
queue.addRequest(() => axios.get('/api/products'), 5);
queue.addRequest(() => axios.get('/api/promotions'), 5);
}
queue.processQueue();