首页 > 解决方案 > 防止并发ajax请求,让他们等待

问题描述

我的客户端 Javascript 应用程序需要来自服务器端的特定数据结构(“列表”)。应用程序中的几个不同位置需要访问列表。启动时,这些地方都会发出请求,这会导致对服务器的多个并发请求,以获得相同的数据结构。

我只想向服务器发出一个请求,并让所有请求者简单地得到一个在请求返回时解决的承诺。

我认为方法是创建一个数组或一组承诺。如果第一个请求正在进行中,则每个后续请求都会创建一个 Promise 并将其添加到堆栈中。当响应返回时,系统将遍历堆栈并使用结果解析所有承诺。

问题是我无法找出正确的语法来让它工作。这是我到目前为止所拥有的:

let lists = [];
let loading = false;
let promises = [];

function getLists() {
  if (lists.length > 0) {
    // return cached copy
    return Promise.resolve(lists);
  }

  /*
  This method can get called several times in quick succession on startup.
  To prevent sending multiple requests to the server, we maintain 
  a stack of promises. If there is already a request in-flight, then just
  add a promise to the stack and return it. Then resolve all promises
  in the stack when the request returns.
  */
  let prom = new Promise();  // BAD, NOT ALLOWED
  promises.push(prom);
  if (!loading) {
    callListsApi(); // async call, resolves promises
  }
  return prom;
}

function callListsApi() {
  loading = true;
  axios.get("/lists").then(
    response => {
      loading = false;
      if (!response.data || response.data.length == 0) {
        lists = [];
      } else {
        lists = response.data;
      }
      for (let i = 0; i < promises.length; i++) {
        promises[i].resolve(lists); // give all the callers their lists
      }
      promises = [];
    },
    error => {
      loading = false;
      util.handleAxiosError(error);
      let msg = util.getAxiosErrorText(error);
      for (let i = 0; i < promises.length; i++) {
        promises[i].reject(msg);
      }
      promises = [];
    }
  );
}

这是行不通的,因为你不能创建一个裸 Promise() 而不在其中放置某种 executor 函数。

我怎样才能重写它以使其工作?

标签: javascriptajaxconcurrencypromiseaxios

解决方案


弄清楚了。答案不是创建一堆承诺。只是一遍又一遍地向每个请求者返回相同的承诺。我们维护一个主要的承诺,它仅在请求进行中时才存在。这要简单得多。

let lists = [];
let listPromise = null;

function getLists() {
  if (lists.length > 0) {
    // return cached copy
    return Promise.resolve(lists);
  }

  if (listPromise != null) {
    // if we get here, then there is already a request in-flight
    return listPromise;
  }

  listPromise = callListsApi();
  return listPromise;
}

function callListsApi() {
  return axios.get("/lists").then(
    response => {
      if (!response.data || response.data.length == 0) {
        lists = [];
      } else {
        lists = response.data;
      }
      listPromise = null;
      return lists;
    },
    error => {
      util.handleAxiosError(error);
      listPromise = null;
      return util.getAxiosErrorText(error);
    }
  );
}

推荐阅读