實現一個封裝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