定义
当前网络请求完成时(成功、失败、或者超时),才能进行下一个网络请求,这就是网络请求队列。
使用场景
- 客户端短时间内产生的网络请求次数过多,造成服务器压力过大,需要限制
- 下一个网络请求的参数依赖上一个网络请求的结果
- 每次网络请求的参数结构和返回结果基本一样
- 解决小程序只能同时并发5个请求的限制
网络请求队列的代码实现
let currentRequestQueue = []; //当前网络请求队列
let currentRequestResponse = true; //当前网络请求响应状态
let requestTimes = 0; //网络请求次数
let responseFailTimes = 0; //网络反馈失败次数
let responseSuccessTimes = 0; //网络反馈成功次数
/** 网络请求队列函数 */
function requestQueue(){
//网络请求队列里还有网络请求,当前请求反馈有结果时才进行下一个请求
if(this.currentRequestQueue.length > 0 && this.currentRequestResponse){
this.updateData(this.currentRequestQueue.shift());
}
}
/** 请求更新服务器上的数据 */
function updateData(params){
requestTimes++; //网络请求次数加1
currentRequestResponse = false; //已发送请求,但未响应
fetch('http://127.0.0.1:8080/app/update',{
method:'POST',
headers:{"Content-Type": "application/json;charset=UTF-8"},
body:JSON.stringify(params) //通常需要转换成字符串后服务器才能解析
}).then((response) => response.json())
.then( res=>{
if(res.header.statusCode == 'success'){ //请求成功
responseSuccessTimes++; //网络反馈成功次数加1
}else{ //请求失败
currentRequestQueue.unshift(params); //添加到队列的开头再次请求
responseFailTimes++; //网络反馈失败次数加1
}
currentRequestResponse = true; //当前网络请求已响应
requestQueue(); //进行下一个请求
requestResult(); // 所有网络请求结果
}).catch( err=>{ //请求出错
currentRequestQueue.unshift(params); //添加到队列的开头再次请求
responseFailTimes++; //网络反馈失败次数加1
currentRequestResponse = true; //当前网络请求已响应
requestQueue(); //进行下一个请求
requestResult(); // 所有网络请求结果
})
}
/** 根据网络反馈次数判断当前所有网络请求的结果 */
function requestResult(){
console.log(`网络请求次数:${requestTimes}`,`失败:${responseFailTimes}`,`成功:${responseSuccessTimes}`);
if(responseSuccessTimes == requestTimes){ //请求次数和成功次数相等
initAfterRequest();
console.log('网络请求全部成功');
}else if(responseFailTimes == requestTimes){ //请求次数和失败次数相等
initAfterRequest();
console.log('网络请求全部失败');
}else if(responseSuccessTimes + responseFailTimes == requestTimes){ //请求次数和反馈次数相等
initAfterRequest();
console.log('网络请求部分成功');
}
}
/** 所有网络请求得到结果后重置次数 */
function initAfterRequest(){
requestTimes = 0;
responseFailTimes = 0;
responseSuccessTimes = 0;
}
//手动创建网络请求队列
for(let i = 0; i < 10; i++){
//请求参数
let params = {
userId:'abcd123456', //用户id
data:i //当前的数据,这里用i来模拟,实际项目请求的参数更复杂
}
currentRequestQueue.push(params);
}
requestQueue(currentRequestQueue); //调用网络请求队列
上述网络请求使用的是fetch请求,也可以更换成Ajax请求的方式。
扩展:
- 当网络队列请求次数过多,需要过多时间来处理时,为提升用户体验,可以设置一个按钮让用户手动停止网络请求队列
实现方法:首先定义一个变量isStopRequest
,然后在requestQueue
里判断此变量即可
let isStopRequest = false; //是否手动停止网络请求队列
function requestQueue(){
if(isStopRequest){
console.log('手动停止网络请求队列');
return;
}
if(this.currentRequestQueue.length > 0 && this.currentRequestResponse){
this.updateData(this.currentRequestQueue.shift());
}
}
- 当网络状况不好时,请求失败次数超过3次时,自动停止网络请求队列
实现方法:在requestQueue
里判断变量responseFailTimes即可
function requestQueue(){
//当请求失败超过3次后,根据实际也可以定义其他基准次数,表明当前网络状况不好,这时可以停止网络请求队列
if(responseFailTimes >= 3){
console.log('网络请求队列因网络失败次数过多自动停止');
return;
}
if(this.currentRequestQueue.length > 0 && this.currentRequestResponse){
this.updateData(this.currentRequestQueue.shift());
}
}
-
如果对于数据比较敏感或者对数据的完整性要求较高,当停止网络请求队列时可以将当前还未发送的网络请求队列保存在本地缓存,当用户再次触发时读取缓存并将上次未发送的请求加入到网络请求队列。
-
当网络意外断开时,当前的网络请求会立即返回失败的回调,并将当前网络请求队列保存到缓存中。而当前的请求其实已经成功发送到服务器上,只是客户端还没有收到请求成功返回的数据,当下次再次读取缓存并将上次未发送的请求加入到网络请求队列,就会导致比实际上多了一个请求,造成数据错误。
解决办法:
- 客户端:在生成网络请求的时候加入当前请求的时间戳,代码如下:
for(let i = 0; i < 10; i++){
let params = {
userId:'abcd123456',
data:i ,
synchronized_time:String(new Date().getTime()) //时间戳字符串
}
currentRequestQueue.push(params);
}
- 服务器端:判断当前请求的时间戳跟上次请求的时间戳是否一样,如果一样,返回请求成功,但此次请求改变的数据不更新到数据库中。