Skip to content

优化请求接口的并发

请求队列

Request Queue

请求队列可以确保在指定时间内允许并发执行的请求的最大个数

js
class RequestQueue {
  constructor(maxConcurrent) {
    this.maxConcurrent = maxConcurrent; // 最大请求并发数
    this.currentConcurrent = 0;         // 当前请求并发数
    this.queue = [];                    // 请求队列
  }

  add(request) {
    return new Promise((resolve, reject) => {
      this.queue.push({ request, resolve, reject });
      this.processQueue();
    });
  }

  processQueue() {
    if (this.queue.length > 0 && this.currentConcurrent < this.maxConcurrent) {
      const { request, resolve, reject } = this.queue.shift();
      this.currentConcurrent++;
      request()
        .then(resolve)
        .catch(reject)
        .finally(() => {
          this.currentConcurrent--;
          this.processQueue();
        });
    }
  }
}

// --------------------------------------------------------------------------------
// --------------------------------------------------------------------------------

const requestUrls = [
  "请求地址",
  "请求地址",
  "请求地址",
  // ...
]
const requestJobs = requestUrls.map((url) => {
  return () =>
    fetch(url)
      .then((response) => {
        if (!response.ok) throw new Error(url,response.status);
        return response.json();
      })
      .then((result) => console.log(result))
      .catch((err) => console.error(err));
});

const requestQueue = new RequestQueue(5); // 比如设置最大可以并发5个请求

Promise.all(requestJobs.map((request) => requestQueue.add(request)))
  .then((result) => console.log("所有请求全部完成", result))
  .catch((error) => console.log("请求失败", error));

防抖

Debounce

防抖可以确保在指定时间内只执行一次处理,避免频繁发起请求

常用于输入框内容的的关联提示等处理

js
function debounce(callback, wait) {
  let timeout;
  return function (...args) {
    clearTimeout(timeout);
    timeout = setTimeout(() => {
      callback.apply(this, args);
    }, wait);
  };
}

// --------------------------------------------------------------------------------
// --------------------------------------------------------------------------------

const debouncedFetcher = debounce((url) => {
  fetch(url)
    .then((response) => {
      if (!response.ok) throw new Error(url, response.status);
      return response.json();
    })
    .then((result) => console.log(result))
    .catch((err) => console.error(err));
}, 4000);

debouncedFetcher("请求地址");

节流

Throttle

节流可以确保在指定间隔内只执行一次处理,避免频繁发起请求

常用于页面 resize、scroll 等处理

js
function throttle(callback, interval) {
  let inThrottle = false;
  return function (...args) {
    if (!inThrottle) {
      callback.apply(this, args);
      inThrottle = true;
      setTimeout(() => {
        inThrottle = false;
      }, interval);
    }
  };
}

// --------------------------------------------------------------------------------
// --------------------------------------------------------------------------------

const throttleFetcher = throttle((url) => {
  fetch(url)
    .then((response) => {
      if (!response.ok) throw new Error(url, response.status);
      return response.json();
    })
    .then((result) => console.log(result))
    .catch((err) => console.error(err));
}, 2000);

throttleFetcher("请求地址");

分页加载

js
const pageSize = 20;
let currentPage = 1;

let isLoading = false;

function loadingMore(callback = null) {
  if (isLoading) {
    return;
  }
  isLoading = true;

  fetch(`请求地址?size=${pageSize}&page=${currentPage}`)
    .then((response) => {
      if (!response.ok) throw new Error(url, response.status);
      return response.json();
    })
    .then((result) => {
      currentPage++;

      const container = document.getElementById("item-container");
      result.data.forEach((item) => {
        const itemElement = document.createElement("div");
        itemElement.textContent = item.name;
        container.appendChild(itemElement);
      });
    })
    .catch((err) => {
      console.error(err);
    })
    .finally(() => {
      isLoading = false;
    });
}

// 初始化加载
loadingMore();

// 页面滚动时到底后加载
window.addEventListener(
  "scroll",
  throttle(() => {
    if (window.innerHeight + window.scrollY >= document.body.offsetHeight) {
      loadingMore();
    }
  }, 300),
);

最近更新: