前端控制请求的几种方式

并发请求

  • 方式1
    • 比如一个下载页面,要发起10个请求才能获取全量数据,希望控制最多5个并发请求。
    • 通过Promise.all、Promise.race进行控制
async function concurrentControl(poolLimit, requestPool) {
  // 存放所有请求返回的 promise
  const ret = [];
  // 正在执行的请求,用于控制并发
  const executing = [];

  while (requestPool.length > 0) {
    const request = requestPool.shift();
    // 将请求Promise化
    const p = Promise.resolve().then(() => request());
    ret.push(p);
    // 异步删除已有结果的请求
    const e = p.then(() => executing.splice(executing.indexOf(e), 1));
    executing.push(e);
    // 当超过并发限制,通过Promise.race进行筛选,从而通过.then从executing中删除掉
    if (executing.length >= poolLimit) {
      await Promise.race(executing);
    }
  }
  return Promise.all(ret);
}
  • 方式2
function multiRequest(request = [], maxNum) {
  // 请求总数量
  const len = request.length;
  // 根据请求数量创建一个数组来保存请求的结果
  const result = Array.from({ length: len }, (_, index) => false);
  // 当前完成的数量
  let count = 0;

  return new Promise((resolve, reject) => {
    // 请求maxNum个
    while (count < maxNum) {
      next();
    }

    function next() {
      let current = count++;
      // 处理边界条件
      if (current >= len) {
        // 请求全部完成就将promise置为成功状态, 然后将result作为promise值返回
        !result.includes(false) && resolve(result);
        return;
      }
      const req = request[current];

      req()
        .then((res) => {
          // 保存请求结果
          result[current] = res;
          // 请求没有完成
          if (current < len) {
            next();
          }
        })
        .catch((err) => {
          result[current] = err;
          reject(result)
        });
    }
  });
}

丢弃请求

  • 方式1(react 版本):
    • 数据变化放弃之前请求
    • 通过一个开关来丢弃结果
useEffect(() => {
  // 有效性标识
  let didCancel = false;
  const fetchData = async () => {
    const result = await getData(query);
    // 更新数据前判断有效性
    if (!didCancel) {
      setResult(result);
    }
  }
  fetchData();
  return () => {
    // query 变更时设置数据失效
    didCancel = true;
  }
}, [query]);
  • 方式2:
function latestReq() {

  let last;
  function request(params) {

    axios.then(() => {
      if (last !== params) {
        //...
      }
    })
    last = params;

  }
  return request;
}
  • 方式3:AbortController

淘汰请求

  • 短时间内发送多个请求,而且前面发出的请求结果不能覆盖后面的(网络阻塞可能导致先发出的请求后返回)
    • 通过一个计数器来实现
// 请求序号
let seqenceId = 0;
// 上一个有效请求的序号
let lastId = 0;

function App() {
  const [query, setQuery] = useState('react');
  const [result, setResult] = useState();

  useEffect(() => {
    const fetchData = async () => {
      // 发起一个请求时,序号加 1
      const curId = ++seqenceId;
      const result = await getData(query);
      // 只展示序号比上一个有效序号大的数据
      if (curId > lastId) {
        setResult(result); 
        lastId = curId;
      } else {
        console.log(`discard ${result}`); 
      
    fetchData();
  }, [query]);

  return (
    ...
  );
}

串行请求

详情

node 回调风格

详情

高优先级和低优先级请求

  • 低优先级任务执行时机
    • 定时器四秒后
    • 遇到滑动、点击等事件时立即调用(通过发布订阅实现)
    • 高优先级任务完成后调用
import axios from 'axios';

// 队列用于存储待处理的请求
const requestQueue = [];

// 高优先级请求的标识符
const HIGH_PRIORITY_REQUEST = '/high-priority-endpoint';

// 请求拦截器
axios.interceptors.request.use(config => {
  if (config.url === HIGH_PRIORITY_REQUEST) {
    // 如果是高优先级请求,立即发送
    return config;
  } else {
    // 如果不是,将请求推迟,存入队列
    return new Promise(resolve => {
      requestQueue.push(() => resolve(config));
    });
  }
});

// 响应拦截器
axios.interceptors.response.use(response => {
  if (response.config.url === HIGH_PRIORITY_REQUEST) {
    // 如果高优先级请求完成,执行队列中的所有请求
    requestQueue.forEach(executeRequest => executeRequest());
    // 清空队列
    requestQueue.length = 0;
  }
  return response;
}, error => {
  return Promise.reject(error);
});

// 发起请求
function sendRequest(config) {
  axios(config).then(response => {
    console.log('请求成功:', response);
  }).catch(error => {
    console.log('请求失败:', error);
  });
}

// 示例:发起一个高优先级的请求
sendRequest({ url: HIGH_PRIORITY_REQUEST });

// 示例:发起其他普通优先级的请求
sendRequest({ url: '/normal-priority-endpoint-1' });
sendRequest({ url: '/normal-priority-endpoint-2' });
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值