返回

Promise + Async&Await + Array.reduce + 函数递归:优雅解决网络/接口请求的依次/排队不间断间隔访问

前端

需求背景

试想在一个需要频繁更新数据的场景(例如:监控、图表类),常规方法是设置一个间隔 N 秒的定时器 setInterval。但是这种方式存在一个问题,当前一个请求时间过长时(超过了间隔时间),后一个请求就会被阻塞,导致数据更新不及时。

解决思路

为了解决上述问题,我们可以利用 Promise、Async&Await、Array.reduce 和函数递归来实现网络/接口请求的依次/排队不间断间隔访问。具体思路如下:

  1. 首先,我们将所有的请求封装成一个 Promise 数组。
  2. 然后,利用 Array.reduce 方法,对 Promise 数组进行依次执行。
  3. 在每个 Promise 执行时,我们利用 Async&Await 等待其执行完毕,并记录其执行时间。
  4. 如果当前 Promise 执行时间超过了预设的间隔时间,则在下一个 Promise 执行前,添加一个等待时间,使其与预设的间隔时间相等。
  5. 通过函数递归,不断重复上述步骤,直到所有的请求都执行完毕。

代码示例

const requests = [
  fetch('https://example.com/api/v1/data1'),
  fetch('https://example.com/api/v1/data2'),
  fetch('https://example.com/api/v1/data3')
];

const interval = 1000; // 预设的间隔时间

const fetchWithInterval = async (requests, interval) => {
  const results = [];

  const reducePromise = requests.reduce(async (previousPromise, currentRequest) => {
    await previousPromise;

    const startTime = Date.now();
    const response = await currentRequest;
    const endTime = Date.now();

    const executionTime = endTime - startTime;
    if (executionTime > interval) {
      await new Promise(resolve => setTimeout(resolve, interval - executionTime));
    }

    results.push(response);
  }, Promise.resolve());

  return reducePromise.then(() => results);
};

fetchWithInterval(requests, interval).then(results => {
  console.log(results);
});

优点

这种方法具有以下优点:

  • 可以确保请求依次/排队执行,不会相互阻塞。
  • 可以指定预设的间隔时间,确保请求之间有一定的时间间隔。
  • 可以通过函数递归不断重复执行请求,直到所有的请求都执行完毕。

总结

利用 Promise、Async&Await、Array.reduce 和函数递归,可以轻松实现网络/接口请求的依次/排队不间断间隔访问,解决定时器 setInterval 在请求时间过长时的缺陷。这种方法简单易用,并且具有很强的灵活性。