实现一个封装ajax器,功能有ios
实现一个队列,通常要实现进队、出队的方法,符合先进先出的原则,同时也要实现查询队满、队空的状态。 由于若是进出队次数过多会形成数组过大,为了避免形成浪费,这里就实现的是循环队列。面试
//实现一个队列
class Queue{
constructor(size){
this.size = size;
this.data = Array(size);
this.front = 0;
this.rear = 0;
}
in(url){
if(this.isFull()) return false;
this.data[this.rear] = url;
this.rear = (this.rear+1)%this.size;
return true;
}
out(){
let res = null;
if(this.isEmpty()) return res;
res = this.data[this.front];
this.data[this.front] = null;
this.front = (this.front+1)%this.size;
return res;
}
isFull(){
return this.front===this.rear&&this.data[this.size-1];
}
isEmpty(){
return this.front===this.rear&&!this.data[this.size-1];
}
}
复制代码
Promise.race(iterable) 方法返回一个 promise,一旦迭代器中的某个promise解决或拒绝,返回的 promise就会解决或拒绝。ajax
咱们利用的就是race方法返回一个被包装的Promise,咱们基于这个作回调处理,里面有用来取消的Promise,和原始的Promise,当须要取消Promise,用来取消的Promise resolve就能够了。axios
//返回能够取消的Promise
class CanCancelPromise{
constructor(promise){
let resolve,reject,cancelP;
if(promise instanceof Promise){
cancelP = new Promise(function(res, rej){
resolve = res;
reject = rej;
});
this.promise = Promise.race([promise, cancelP]);
this.cancel = ()=>{
resolve(CancelPromise);
};
}else{
throw new Error("请传入Promise对象")
}
}
}
复制代码
当前面两部准备工做完成,就能够借助它们来实现ajax封装器了。数组
class axios{
/**
* 初始化axios
* @param maxSize 限制同时请求的ajax请求数量m
* @param reTryCount 重试次数
* @param timeout 超时设定时间
* @param poolSize 请求池的大小
*/
constructor(maxSize=3,reTryCount=3,timeout = 100,poolSize=100){
this.requests = new Queue(poolSize);
this.maxSize = maxSize;
this.curSize = 0;
this.timeout = timeout;
this.reTryCount = reTryCount;
}
//传入请求url和回调函数
post(url,handle=null){
if(this.requests.in(url)){
return this.tryRequestUrl(handle);
}else{
throw new Error("请求池已满");
}
}
//存入请求池,开始根据最大请求判断是否发出请求
tryRequestUrl(handle){
if(this.curSize<this.maxSize){
let url = this.requests.out();
if(url){
console.log(`开始链接${url}`);
this.reTryRequest(url,handle,this.timeout,this.reTryCount);
this.curSize ++;
}
}else{
console.log(`等待链接`);
}
}
// 请求并负责重试
reTryRequest(url,handle, wait,num) {
let timeout, i=1;
let request = (url)=>{
//模拟url请求,现实场景中能够fetch代替
//这里的请求很容易超时
let promiseObj = new CanCancelPromise(new Promise((resolve, reject) => {
setTimeout(resolve, Math.random()*1000);
}));
promiseObj.promise.then((value)=>{
if(value===CancelPromise){
console.log("取消成功");
return;
}
if(timeout){
clearInterval(timeout);
timeout = null;
}
handle(value);
console.log(`请求${url}第${i-1}次成功`);
this.curSize--;
this.tryRequestUrl();
i = num;
});
return promiseObj;
};
let pObj = request(url);
//负责重试
timeout = setInterval(() => {
pObj.cancel();
if(i===num){
clearInterval(timeout);
timeout = null;
console.log(`请求${url}重试${i}次失败,再也不重试!`);
}else{
pObj = request(url);
console.log(`请求${url}重试${i}次失败`);
this.curSize--;
this.tryRequestUrl();
}
i++;
}, wait);
}
}
复制代码
测试代码promise
let a = new axios();
a.post("baidu1.com");
a.post("baidu2.com");
a.post("baidu3.com");
a.post("baidu4.com");
a.post("baidu5.com");
a.post("baidu6.com");
复制代码
做者菜,若有不对,请快点指出,多多见谅!bash