【问题标题】:Prevent concurrent ajax requests, make them wait防止并发ajax请求,让他们等待
【发布时间】:2020-08-17 02:08:54
【问题描述】:

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

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

我认为方法是创建一个数组或一组承诺。如果第一个请求正在进行中,那么每个后续请求都会导致创建一个 Promise 并将其添加到堆栈中。当响应返回时,系统会遍历堆栈并使用结果解析所有的 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 函数。

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

【问题讨论】:

    标签: javascript ajax concurrency promise axios


    【解决方案1】:

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

    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);
        }
      );
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-06-09
      • 1970-01-01
      • 1970-01-01
      • 2018-08-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多