711 发送请求失败_Promise请求异常处理

博客围绕前后端通信时前端请求后端接口的问题展开。前端常将请求封装成Promise形式,文中指出请求超时和数据请求失败的问题。对于请求超时,可设置超时时间并用Promise.race解决;对于数据请求失败,可弃用Promise.all改用Promise.allSettled,并对失败接口重试。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

9d7f3c5adc2e3c17107d6aa70a9a7f16.png

在前后端的通信过程中前端经常会将请求封装成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

如有错误烦请斧正,欢迎点赞,收藏,评论。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值