Search code examples
javascriptasynchronousgetpromisehttprequest

Javascript: Add timeout after every request in Promise.all Map function


For the following function, I have to add a timeout after every GET request in array ajaxUrls. All the XHR GET request are in array ajaxUrls.

function getAllSearchResultProfiles(searchAjaxUrl) {
  var ajaxUrls = [];
  for (var i = 0; i < numResults; i += resultsPerPage) {
    ajaxUrls.push(searchAjaxUrl + "&start=" + i);
  }
  return Promise.all(ajaxUrls.map(getSearchResultsForOnePage))
    .then(function(responses) {
      return responses.map(function(response) {
        if (response.meta.total === 0) {
          return [];
        }
        return response.result.searchResults.map(function(searchResult) {
          return (searchResult);
        });
      });
    })
    .then(function(searchProfiles) {
      return [].concat.apply([], searchProfiles);
    })
    .catch(function(responses) {
      console.error('error ', responses);
    });
}

function getSearchResultsForOnePage(url) {
  return fetch(url, {
      credentials: 'include'
    })
    .then(function(response) {
      return response.json();
    });
}

I want a certain timeout or delay after every GET request. I am facing difficulty in where exactly to add the timeout.


Solution

  • If you want to make requests in serial, you shouldn't use Promise.all, which initializes everything in parallel - better to use a reduce that awaits the previous iteration's resolution and awaits a promise-timeout. For example:

    async function getAllSearchResultProfiles(searchAjaxUrl) {
      const ajaxUrls = [];
      for (let i = 0; i < numResults; i += resultsPerPage) {
        ajaxUrls.push(searchAjaxUrl + "&start=" + i);
      }
      const responses = await ajaxUrls.reduce(async (lastPromise, url) => {
        const accum = await lastPromise;
        await new Promise(resolve => setTimeout(resolve, 1000));
        const response = await getSearchResultsForOnePage(url);
        return [...accum, response];
      }, Promise.resolve([]));
    
      // do stuff with responses
      const searchProfiles = responses.map(response => (
        response.meta.total === 0
        ? []
        : response.result.searchResults
      ));
      return [].concat(...searchProfiles);
    }
    

    Note that only asynchronous operations should be passed from one .then to another; synchronous code should not be chained with .then, just use variables and write the code out as normal.