页面如何减少请求次数,前端如何实现一个页面请求共用
大家好,我是Sven,最近遇到一个问题需要前端页面实现重复请求共用,我这边写了个简单的的方案文档,包含基于 Vue 2(ES5 语法)的实现代码,以及事件命名和定时刷新请求开关的考虑:
页面接口请求数据共用方案文档
一、方案背景
当前页面存在多个功能模块均需调用 data 接口获取数据的情况,原直接使用 ajax 的方式存在请求混乱、资源浪费等问题。为优化数据请求流程,提高数据获取效率,降低接口调用频率,决定将 data 接口调用从直接 ajax 方式改为发布订阅模式实现,并且基于 Vue 2(ES5 语法)进行开发。
二、核心目标
- 采用发布订阅模式统一管理页面内
data接口调用,实现数据请求的有序处理。 - 当多个功能模块请求数据时,确保同一时间只有一个请求去调用
ajax获取数据,其他请求排队等待,减少接口并发压力。 - 定义两种数据请求事件类型:即时请求和定时刷新请求,满足不同场景下的数据获取需求。
- 使用 JavaScript ES5 语法结合 Vue 2 实现方案,代码简洁高效,并添加注释和日志输出。
- 提供定时刷新请求开关,方便控制定时刷新功能。
三、方案设计
3.1 整体架构
- 事件中心:作为发布订阅模式的核心,负责接收各功能模块的订阅请求,管理请求队列,处理数据请求事件。在 Vue 2 中可借助
pmBusiness对象的emit和on方法实现事件的发布与订阅。 - 功能模块:向事件中心订阅
data接口数据,根据自身需求发起即时请求或定时刷新请求。 - 数据获取模块:当事件中心确定需要调用
ajax获取数据时,由数据获取模块执行ajax请求,并将获取到的数据返回给事件中心。
3.2 事件类型
- 即时请求事件:功能模块首次加载或有即时数据需求时,向事件中心发起即时请求。事件中心按时间顺序将请求加入队列,依次处理。事件名:
IMMEDIATE_DATA_REQUEST - 定时刷新事件:设定固定时间间隔(如 30 秒),由事件中心定时触发
data接口数据请求,获取最新数据后通知所有订阅的功能模块。事件名:TIMED_DATA_REFRESH
3.3 请求处理流程
- 请求入队:当功能模块发起
data接口数据请求时,无论即时请求还是定时刷新请求,均将请求加入事件中心的请求队列,事件中心记录请求时间戳,按时间顺序排序。 - 首位请求处理:事件中心优先处理队列中排在第一位的请求。若当前已有缓存数据,直接判断数据是否满足该请求需求(如数据是否过期)。若满足则直接返回数据给请求的功能模块;若不满足或无缓存数据,则调用
ajax获取数据。 - 后续请求处理:首位请求调用
ajax获取数据返回后,事件中心依次处理队列中后续请求。对于每个后续请求,检查当前缓存数据是否满足其需求,若满足则直接返回数据;若不满足,则继续判断该请求是否为即时请求。若是即时请求,则重新调用ajax获取数据;若是定时刷新请求且距离上次刷新时间未超过设定间隔(如 30 秒),则不调用ajax,等待下一次定时刷新。 - 数据更新与通知:当
ajax获取到新数据后,事件中心更新缓存数据,并通知所有订阅的功能模块数据已更新,功能模块根据新数据进行相应处理。
3.4 首次加载多请求排队机制
在首次加载时,多个功能模块可能同时向事件中心请求数据。为确保事件中心只查一次 data 接口,让后面的请求排队,事件中心在接收到第一个请求时,会立即标记为正在请求数据。后续请求进入队列时,若发现正在请求数据,则直接排队等待。当第一个请求获取到数据后,更新缓存数据并依次处理队列中的后续请求。
3.5 定时刷新请求开关
提供一个开关变量,用于控制定时刷新请求的开启和关闭。当开关开启时,事件中心按照设定的时间间隔触发定时刷新请求;当开关关闭时,停止定时刷新请求。
四、实现细节
4.1 事件中心实现
// 事件中心构造函数
function EventCenter(pmBusiness) {
this.pmBusiness = pmBusiness;
// 存储请求队列
this.requestQueue = [];
// 存储缓存数据
this.cacheData = null;
// 记录上次刷新时间
this.lastRefreshTime = null;
// 标记是否正在请求数据
this.isRequesting = false;
// 定时刷新请求开关
this.timedRefreshEnabled = false;
// 定时器 ID
this.timerId = null;
// 监听即时请求事件
this.pmBusiness.on('IMMEDIATE_DATA_REQUEST', this.handleImmediateRequest.bind(this));
// 监听定时刷新事件
this.pmBusiness.on('TIMED_DATA_REFRESH', this.handleTimedRefreshRequest.bind(this));
}
// 处理即时请求方法
EventCenter.prototype.handleImmediateRequest = function (callback) {
var request = {
type: 'immediate',
callback: callback,
timestamp: new Date().getTime()
};
// 将请求加入队列
this.requestQueue.push(request);
console.log('即时请求已加入队列:', request);
// 处理请求队列
this.processQueue();
};
// 处理定时刷新请求方法
EventCenter.prototype.handleTimedRefreshRequest = function (callback) {
var request = {
type: 'timed',
callback: callback,
timestamp: new Date().getTime()
};
// 将请求加入队列
this.requestQueue.push(request);
console.log('定时刷新请求已加入队列:', request);
// 处理请求队列
this.processQueue();
};
// 处理请求队列方法
EventCenter.prototype.processQueue = function () {
if (this.isRequesting || this.requestQueue.length === 0) {
return;
}
// 取出队列首位请求
var firstRequest = this.requestQueue.shift();
this.isRequesting = true;
console.log('开始处理请求:', firstRequest);
// 检查缓存数据
if (this.cacheData && this.isDataValid()) {
console.log('使用缓存数据');
firstRequest.callback(this.cacheData);
this.isRequesting = false;
// 继续处理后续请求
this.processQueue();
} else {
console.log('调用 ajax 获取数据');
// 调用数据获取模块获取数据
this.fetchData(function (data) {
this.cacheData = data;
this.lastRefreshTime = new Date().getTime();
firstRequest.callback(data);
this.isRequesting = false;
// 继续处理后续请求
this.processQueue();
}.bind(this));
}
};
// 检查数据是否有效方法
EventCenter.prototype.isDataValid = function () {
if (!this.lastRefreshTime) {
return false;
}
var now = new Date().getTime();
// 假设数据有效期为 30 秒
return (now - this.lastRefreshTime) < 30000;
};
// 数据获取方法
EventCenter.prototype.fetchData = function (callback) {
// 模拟 ajax 请求
setTimeout(function () {
var data = { message: '这是从 data 接口获取的数据' };
console.log('成功获取数据:', data);
callback(data);
}, 1000);
};
// 开启定时刷新方法
EventCenter.prototype.startTimedRefresh = function () {
this.timedRefreshEnabled = true;
this.timerId = setInterval(function () {
if (this.timedRefreshEnabled) {
this.pmBusiness.emit('TIMED_DATA_REFRESH', function (data) {
console.log('定时刷新接收到数据:', data);
});
}
}.bind(this), 30000);
};
// 关闭定时刷新方法
EventCenter.prototype.stopTimedRefresh = function () {
this.timedRefreshEnabled = false;
clearInterval(this.timerId);
};
4.2 功能模块调用示例
// 假设 pmBusiness 是一个 Vue 2 对象,有 emit 和 on 方法
var pmBusiness = new Vue();
// 创建事件中心实例
var eventCenter = new EventCenter(pmBusiness);
// 功能模块 1 发起即时请求
function module1Callback(data) {
console.log('功能模块 1 接收到数据:', data);
}
pmBusiness.emit('IMMEDIATE_DATA_REQUEST', module1Callback);
// 开启定时刷新
eventCenter.startTimedRefresh();
五、测试与验证
- 功能测试:模拟多个功能模块同时发起即时请求和定时刷新请求,验证事件中心是否按照设计流程处理请求,功能模块是否能正确获取数据。
- 性能测试:在高并发情况下,测试接口调用次数、响应时间等性能指标,评估方案是否达到优化效果,是否存在性能瓶颈。
- 数据一致性测试:检查不同功能模块获取到的数据是否一致,确保数据在更新和分发过程中不出现错误。
- 定时刷新开关测试:测试定时刷新请求开关的开启和关闭功能,验证开关状态是否能正确控制定时刷新请求的触发。
六、风险与应对措施
- 数据缓存问题:若缓存数据未及时更新或更新错误,可能导致功能模块获取到错误数据。应对措施:加强数据更新逻辑的测试,增加数据校验机制,确保缓存数据的准确性。
- 请求队列堵塞:在极端情况下,请求队列可能因大量请求而堵塞,影响数据获取效率。应对措施:设置请求队列长度限制,当队列满时,可根据策略(如丢弃旧请求或延迟处理)进行处理,同时优化请求处理流程,提高处理速度。
- 接口调用失败:
ajax请求可能因网络问题或接口服务异常导致失败。应对措施:增加请求重试机制,设定合理的重试次数和间隔时间;同时在接口调用失败时,及时通知功能模块,以便进行相应的错误提示或业务处理。 - 定时刷新问题:定时刷新可能会导致不必要的接口调用,增加服务器压力。应对措施:合理设置定时刷新时间间隔,根据业务需求灵活调整开关状态。
以上方案详细说明了基于 Vue 2(ES5 语法)的实现思路和代码示例,包括事件命名、定时刷新请求开关等功能。当然了,还有完善的空间,可以根据实际情况对代码进行调整和扩展。
点击查看代码
作者:SVENNEE
出处:http://www.cnblogs.com/svennee
本文采用知识共享署名-非商业性使用-相同方式共享 2.5 中国大陆许可协议进行许可,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。
如果您觉得此文有帮助,请点击推荐和关注我。您的支持将鼓励我继续创作!

出处:http://www.cnblogs.com/svennee
本文采用知识共享署名-非商业性使用-相同方式共享 2.5 中国大陆许可协议进行许可,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。
如果您觉得此文有帮助,请点击推荐和关注我。您的支持将鼓励我继续创作!

浙公网安备 33010602011771号