【问题标题】:How to handle a lof of Ajax requests on a loop and prevent "Too many requests" using JavaScript如何处理循环中的大量 Ajax 请求并使用 JavaScript 防止“请求过多”
【发布时间】:2021-01-29 01:55:17
【问题描述】:

我正在尝试从 Web 服务中保存一些信息,这是很多数据,我必须发出很多 Ajax 请求,在这么快的许多请求之后,服务器只是抛出“请求太多”,这使得感觉...

我的代码如下所示:

function getDataFromWS()
{
    define some vars
    $ make an ajax request to MY database to get every item i will request on the external WS 
    (that query returns like 150 items to arrayFromResponse)
    
    //Loop into the array with 150 items
    arrayFromResponse.forEach((element)=>{
        //For loop to make request for each day of the month e.g. August 31 days
        for(let i = 1; i <= 31; i++){
            //change uri to match each day using i
            uriData.date = '2020-08-0'+i;

             //This is where after many requests it throws error 429 "Too many"
                $.ajax({
                    data: uriData,
                    url: uri,
                    type: 'GET',
                    async: false,
                    success : function(response){
                        
                            //Save data from response to some arrays I use
                    
                    },
                    error: function(response){
                        console.log(response);
                        console.log('Error');
                    }
                });
        } 
    })
    //After all that looping and requests make a CSV file
    buildCSVfile(dataFromResponses);
}

我需要所有这些代码都是同步的,我假设我需要使用 setTimeout 之类的东西,因为我试过了,但是 buildCSVfile() 函数在循环之前执行,我猜延迟应该在每个 ajax 请求之后在 for 循环的日期中。每个请求可能需要 10 秒,所以它不会说太多请求?所有核心代码都在success函数中。我不需要这个很快,只是为了确保获得所有信息,每个项目和每个月的每一天。

感谢您提供的任何帮助。

【问题讨论】:

  • “我需要所有这些代码都是同步的” 为什么? BTW,如果你添加setTimeout,那么它将不再是同步的。
  • @HereticMonkey 由于保存数据的 CSV 文件,我只需要延迟每个 ajax 请求,并且在 4500 个请求结束时,将文件与所有内容一起保存。它现在可以工作,但只能处理 50 个请求。
  • 考虑另一种不需要同步的技术。查看Sending one AJAX request at a time from a loop的答案

标签: javascript jquery ajax xmlhttprequest


【解决方案1】:

我建议使用 jQuery Defered,因为您已经使用 jQuery。

阅读 jQuery Deferred 以了解内部工作原理。 它基本上实现了一个基于 Promises 的系统。

您的代码最终可能类似于:

function getDataFromWS()
{
  var deferred = new $.Deferred();
  var dataFromResponses = [];
  //   define some vars
  //   $ make an ajax request to MY database to get every item i will request on the external WS 
  //   (that query returns like 150 items to arrayFromResponse)

  var uri = "https://jsonplaceholder.typicode.com/todos/";
  var arrayFromResponse = ["SOME DATA"];
  //Loop into the array with 150 items
  arrayFromResponse.forEach((element)=>{
    //For loop to make request for each day of the month e.g. August 31 days
    for(let i = 1; i <= 10; i++){
      var uriData = {};
      //change uri to match each day using i
      uriData.date = '2020-08-0'+i;

      var def = new $.Deferred();
      //This is where after many requests it throws error 429 "Too many"
      $.ajax({
        data: uriData,
        cache: false,
        url: uri + i,
        type: 'GET',
        async: false,
        success : function(response){
          console.log("Got data at day " + i);
          dataFromResponses.push(response);
        },
        error: function(response){
          deferred.reject(response);
          console.log('Error');
        }
      });
    }
  });
  //After all that looping and requests make a CSV file
  deferred.resolve(dataFromResponses);
  return deferred.promise();
}

// and call it with:

$.when(getDataFromWS()).done(function(dataFromResponses){
  console.log(dataFromResponses);
  // buildCSVfile(dataFromResponses);
}).fail(function(response){
  console.error(response);
});
&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.10.2/jquery.min.js"&gt;&lt;/script&gt;

【讨论】:

  • 它在您的代码 sn-p 上完美运行,但在 .done 函数的 console.log(dataFromResponses) 中,它只是像第一个响应 id 一样打印:i,如果我放一个 console.log (dataFromResponses) 在返回之前,它会打印带有 31 个响应的整个数组...
  • 感谢您的回答,所以使用此代码我不会在多次调用 API 时收到“请求过多”错误?或者使用此代码,我可以使用延迟,这对我来说不会出现该错误是有意义的。
  • 此代码将以“同步”方式处理请求。因此,呼叫不会同时运行。在一定时间内可以进行的调用量仍然可能受到服务器的限制。对您的服务器/后端进行一些试验,看看它是否会遇到任何问题。
【解决方案2】:

我相信这对后端来说是一个挑战——它的 API 应该支持通过一个请求来完成这项任务。 但如果您确定需要发出许多单独的请求,只需使用并发限制 (Live demo):

import CPromise from "c-promise2";
import $ from "jquery";

async function getDataFromWS(url, concurrency) {
  return CPromise.all(
    function* () {
      for (let i = 1; i < 32; i++) {
        const uriData = { date: "2020-08-0" + i };
        yield $.ajax({
          data: uriData,
          url,
          type: "GET",
          dataType: "json",
          async: true
        });
      }
    },
    { concurrency }
  );
}

const buildCSVfile = async (responses) => {
  console.log(`Done: `, responses.map(JSON.stringify));
};

(async () => {
  const data = await getDataFromWS(
    `https://run.mocky.io/v3/753aa609-65ae-4109-8f83-9cfe365290f0?mocky-delay=1s`,
    10 // concurrent request limit 
  );
  await buildCSVfile(data);
})();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-11-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-21
    • 1970-01-01
    • 2023-03-09
    相关资源
    最近更新 更多