
在前后端的通信过程中前端经常会将请求封装成Promise的形式请求后端接口,下面我会列出在请求过程中会经常会出现几个问题并给出自己的解决方案。
1 请求超时
有时候请求发出去接口响应很慢很慢,用户界面一直在等待这个结果的返回才能进行下一步操作这样的用户体验很不友好。需要设置一个请求超时时间,利用Promise.race就可以很好的解决这个问题。
const
2 数据请求失败自动发起请求
在实际的项目开发中遇到这样一个场景,在一个组件中前端需要同时调用5个接口等5个接口返回展示数据(各接口间没有依赖关系)。为了提高效率一开始使用的是Promise.all将5个接口并行发送等待应答,但是Promise.all有个坑就是只要其中一个接口返回的状态是reject整个Promise.all结果就是reject。后来弃用Promise.all改成用Promise.allSettled。(不知道现在babel 支持Promise.allSettled了没有)自己写了一个Promise.allSettled的功能实现。话说回来如果5个并行请求的接口中有一个或者多个接口请求失败需要对这些失败的接口在发起重试接口请求。下面是我的解决方案请求失败的接口在time时间内会发起N次重试如果还是失败则只会返回请求成功的接口数据,如果在n次中请求失败的接口数据返回成功则最终会接收到。
const reject = Promise.reject(1);
const pResolve = (time: number, name: string) => () =>
new Promise(res => {
setTimeout(() => {
res(`${name} , resolved`);
}, time);
});
let idx = 0;
const idxReject = (time: number, name: string, times: number) => () =>
new Promise((resolve, reject) => {
idx++;
setTimeout(() => {
if (times === idx) {
resolve(`${name}这次成功了 ${idx}`);
} else {
reject(`${name}失败 还差${times - idx}次成功`);
}
}, time);
});
type status = "fulfilled" | "rejected";
interface iPromiseResult {
value?: any;
reason?: any;
status: status;
}
const allSettled = async (promises: any[]) => {
if (!Array.isArray(promises)) {
throw "argument is not array";
}
const result: Array<iPromiseResult> = [];
for (let p of promises) {
try {
let promiseReult = await p;
result.push({
status: "fulfilled",
value: promiseReult
});
} catch (e) {
result.push({
status: "rejected",
value: e
});
}
}
return new Promise(res => res(result));
};
const timeOut = (asyncFn: Promise<any>, time: number) => {
return Promise.race([
asyncFn,
new Promise((resolve, reject) => {
setTimeout(() => {
console.log("setTimeout.....");
resolve({
status: "rejected",
reason: "超时间"
});
}, time);
})
]);
};
/***
* @desc
* @param promise
* @param time number 超时时间
* @parm maxTry number 最大发起重试次数
* ***/
const fetchData = async (
promiseArr: Array<Function>,
time: number,
maxTry = 10
) =>
new Promise(async res => {
const getData = (arr: Array<Function>, sucess: Array<iPromiseResult>) =>
new Promise(async resolve => {
const ps = arr.map(fn => fn());
let result = (await allSettled(ps)) as Array<iPromiseResult>;
let reTry: Array<Function> = [];
result.map((item: iPromiseResult, idx: number) => {
if (item.status === "fulfilled") {
sucess.push(item);
} else {
reTry.push(arr[idx]);
}
});
if (reTry.length) {
if (maxTry >= 0) {
maxTry--;
await getData(reTry, sucess);
}
}
return resolve([...sucess]);
});
const result = await timeOut(getData(promiseArr, []), time);
res(result);
});
const test = async () => {
const result = await fetchData(
[
pResolve(1000, "p1 sucess"),
() => reject,
idxReject(1000, "p1 sucess", 1),
pResolve(1000, "p2 sucess")
],
4000
);
// const result = await fetch([() => reject,() => reject],3000); //
console.log(result, "result");
};
test();
在线demo TypeScript Playground
如有错误烦请斧正,欢迎点赞,收藏,评论。