1

I have a function that makes an ajax call and resolves a promise with the result. Unfortunately the API limits results to 100 and I need to use an offset parameter to get the next 100 and so on. How can I make all the needed ajax calls (the API response provides the total number of values so I can determine the number of calls to make) before resolving the promise?

Here is function I was using to just get the first 100 and then resolve:

    let currentOffset = 0;
    let totalCount;
    let offsetCount;

 const makeCall = function(camp) {
        return new Promise(function(resolve, reject) {
            api.get(camp, currentOffset, e => {
                totalCount = e.totalCount;
                offsetCount = Math.floor(totalCount / 100)
                let payload = e.payload;
                for (var a in payload) {

                    myArray.push({
                        'id': payload[a].id,
                        'text': payload[a].text,
                        'url': ads[a].url,
                    });
                }
                resolve();
            });
        });
    };
  • Make multiple promises from calling `makeCall` multiple times, then use `Promise.all` to create another promise that resolves when all are done. Don't write the logic yourself. – Bergi Jul 11 '17 at 01:00
  • Assuming `payload` is an array, [don't use a `for…in` enumeration](https://stackoverflow.com/q/500504/1048572)! – Bergi Jul 11 '17 at 01:01
  • Sounds like you don't know exactly how many items should be returned and you want to determine that based on the number of items returned? You could make a new Promise within the first promise if you expect more results. (this could be made into a function so that all promises you create can make subsequent ones if there are still items). The downside is that this might be slower since you will need to wait until each one is completed to go onto the next – Marios Hadjimichael Jul 11 '17 at 01:01
  • @MariosHadjimichael could you clarify what placing the promise within the promise would look like if there are more than two API calls needed –  Jul 11 '17 at 02:35

2 Answers2

2

The best way to do this would be to create a Promise for each of the ajax calls, and then use Promise.all() to determine when all of the requests have succeeded.

Something like the snippet below. This promise will only resolve once all calls succeed. Remember that it will never resolve if any of the ajax requests fail, so it could be worth adding something to handle that.

let currentOffset = 0;
let totalCount;
let offsetCount;

const makeCall = function(camp) {
    let apiPromises = [];

    // Repeat the below for each ajax request
    apiPromises.push(
    new Promise(function(resolve, reject) {
        api.get(camp, currentOffset, e => {
            totalCount = e.totalCount;
            offsetCount = Math.floor(totalCount / 100)
            let payload = e.payload;
            for (var a in payload) {

                myArray.push({
                    'id': payload[a].id,
                    'text': payload[a].text,
                    'url': ads[a].url,
                });
            }
            resolve();
        });
    }));

    return Promise.all(apiPromises);
};
KenneyE
  • 353
  • 1
  • 12
  • if I don't know the total count until I make the call how can I set a certain number of times to repeag the apiPromises.push –  Jul 11 '17 at 01:48
  • Do you know how many total results to retrieve? It seems like the question here might be how to determine when to stop making ajax calls. – KenneyE Jul 11 '17 at 03:26
  • The total results are given in the ajax response. The response includes an array of objects (payload) and the key total count –  Jul 11 '17 at 11:23
  • That's total results for that individual request? Or total results after all requests are complete? – KenneyE Jul 11 '17 at 16:01
  • E.totalcount is all the records including those that haven't been sent yet –  Jul 11 '17 at 16:02
  • You could use the first call to determine the number of options, store the resolve function in a scope outside of the promise, then create the needed number of ajax calls to get the rest of the values and resolve the first promise, once all other ajax calls have completed. I've added another answer for something like this. – KenneyE Jul 12 '17 at 17:19
2

You could use the first call to determine the number of options, then create the needed number of ajax calls to get the rest of the values and a corresponding promise for each ajax call. Resolve the first promise, once all other ajax calls have completed. That part could be done with Promise.all().

let currentOffset = 0;
let totalCount;
let offsetCount;

const makeCall = function(camp) { 
    // Repeat the below for each ajax request
    return new Promise(function(resolve, reject) {
        let apiPromises = [];

        api.get(camp, currentOffset, e => {
            totalCount = e.totalCount;
            offsetCount = Math.floor(totalCount / 100)
            let payload = e.payload;
            for (var a in payload) {

                myArray.push({
                    'id': payload[a].id,
                    'text': payload[a].text,
                    'url': ads[a].url,
                });
            }

            for (var numCalls = 1; numCalls < offsetCount; numCalls++) {
                // Increment currentOffset here
                apiPromises.push(new Promise(function() {
                    api.get(camp, currentOffset, e => {
                        // Add each value to array
                    }
                }
            }

            Promise.all(apiPromises).then(resolve);
        });
    });
};

There is some details to fill in, but that should have the gist of it.

KenneyE
  • 353
  • 1
  • 12