0

I have two API requests, each of which asynchronously fetch data that must be available before running another function.

I've been looking into Promises, but have no idea how I'd implement them into this scenario.

Using this code, how can I await returned data from these before running my dependent function without using a setTimeout method?:

    var invoices = null;
    var expenses = null
    var invoicesTotal = 0;
    var expensesTotal = 0;


    JA.get('api/' + companyId + '/Invoicing', function(err, data) {

        if (err) {
            console.error('Error getting Invoicing data:', err);
        } else {
            if (data) {
                invoices = data.Items;
                console.log('Successfully retrieved Invoicing data:', data.Items);
            } else {
                console.log('No invoicing data found');
            }
        }

    })

    JA.get('api/' + companyId + '/Expenses', function(err, data) {
        if (err) {
            console.error('Error retrieving expenses data:', err);
        } else {
            if (data) {
                expenses = data.Items;

            } else {
                console.log('No expenses data found');
            }
        }
    })

    /* CALCULATE TOTAL REVENUE */
    function calcRevenue() {
        ....
    }

    setTimeout(function() {
        calcRevenue();
    }, 1000)
nick.cook
  • 2,071
  • 4
  • 18
  • 36

4 Answers4

1

I'm presuming JA is an alias for $

You need to use a promise chain:

JA.get('api/' + companyId + '/Invoicing')
.done(function(result) {
     ...processing of result
     //this resurns the promise so the second done will run
     return JA.get('api/' + companyId + '/Expenses');
})
.done(function(result){
    ..processing of second result
});

No settimeouts.

Liam
  • 27,717
  • 28
  • 128
  • 190
0

You can use Promise.all() to await an array of promises, and only after all have completed do something in the .then()

See MDN docs for more.

Mark
  • 459
  • 2
  • 12
0

While promises may be the 'better' solution, you can do this with by checking your data:

var invoices = null;
var expenses = null;

JA.get('api/' + companyId + '/Invoicing', function(err, data) {
    ...
        if (data) {
            invoices = data.Items;

            // Call calc here
            calcRevenue(); 
        }
    }
})

JA.get('api/' + companyId + '/Expenses', function(err, data) {
    ...
        if (data) {
            expenses = data.Items;

            // And here
            calcRevenue();
        }
    }
})

function calcRevenue()  {
    if (invoices == null || expenses == null) return;

    ... else both have loaded, ready to do the calc
}

If you need to re-call either ajax call then clear the invoices/expenses variables first.

freedomn-m
  • 27,664
  • 8
  • 35
  • 57
  • Not sure why this got a downvote - the question is **not explicitly asking how to use a promise**, *"how can I await returned data from these before running my dependent function without using a setTimeout method"* - which this does exactly. – freedomn-m Mar 21 '18 at 15:21
-1

This answer uses jQuery ajax() instead of get().

You can use the .ajaxStop() event handler:

$(document).ajaxStop(function() {
    // do something after completion of last ajax call
    calcRevenue();
});

Alternatively, for a better control, you can count active ajax calls and execute your desired code when there are no more ongoing ajax.

var active_ajax_calls = 0;

$.ajax({
    url: ...,
    type: 'GET',
    ...
    // With each ajax call on the page, increment the count by 1
    beforeSend: function(xhr) {
        active_ajax_calls++;
    },
    ...
})
.done(function(response) {
    // do stuff
})
.fail(function() {
    // do stuff
})
.always(function() {
    // Decrement the count by 1 
    active_ajax_calls--;
    if(active_ajax_calls == 0) {
        // Do your special stuff that must happen after all ajax
        calcRevenue();
    }
});
Fr0zenFyr
  • 1,899
  • 2
  • 28
  • 48