0

I'm trying to run a function after 1) all loops are completed and 2) all database calls within those loops are completed.

My database call functions (segmentDatabaseCall and stepDatabaseCall) all take some arguments, resolve a Promise and send the data once the call is complete. This is a (very) simplified version of my code:

let localData = {}

segmentDatabaseCall(argument) // Call the database
.then(segmentResult => { // Returns trip segments (array of objects)

  $.each(segmentResult, (segmentIndex, segmentValue) => { // For each trip segment...

    localData['something'] = segmentValue.something // Add some data to local data

    stepDatabaseCall(segmentValue.segment_id) // Call the database once per trip segment...
    .then(stepResult => { // Returns trip steps (array of objects)

      $.each(stepResult, (stepIndex, stepValue) => { // For each trip step...

        localData['something'][i]['something_else'] = stepValue.something_else // Add some data to local data

        // THIS DOESN'T WORK
        const segsDone = segmentIndex >= segmentResult.length - 1;
        const stepsDone = stepIndex >= stepResult.length - 1;
        if (segsDone && stepsDone) {
          // This if statement runs before all calls are finished 1 out of 3 times roughly
        }
      })
    })
  })
})

Database call:

function databaseCall (argument) {
    return new Promise((resolve, reject) => {
        $.ajax({
          url: $phpUrl,
          type: 'post',
            data: {
              'argument': argument      
            }
        })
        .done (function (data) {
            var resultJson = JSON.parse(data)
            resolve(resultJson)
        })
        .fail (function (error) {
            reject(error)
        })
    })
}

I've tried using the answer here, but it runs before all calls are finished 1 in 3 times. I must be missing some counter there?

I also think there's a way to do this using Promise maps, but I can't get my head around it.

Bryce
  • 356
  • 1
  • 16

2 Answers2

0

There something called forkJoin in Rxjs. As I understand your question you can use that for your implementation.

forkJoin(
      this._myService.makeRequest('Request One', 2000),
      this._myService.makeRequest('Request Two', 1000),
      this._myService.makeRequest('Request Three', 3000)
    )
    .subscribe(([res1, res2, res3]) => {
      this.propOne = res1;
      this.propTwo = res2;
      this.propThree = res3;
    });

read more from here.

R0b1n
  • 513
  • 1
  • 5
  • 28
0

Seeing that you are already using JQuery, you can wrap all of your asynchronous calls with the $.when function.

This will allow you to chain together all your promises and manage the completion of all promises with a single .done() function.

https://api.jquery.com/jQuery.when/

From the JQuery website:

$.when( $.ajax( "/page1.php" ), $.ajax( "/page2.php" ) ).done(function( a1, a2 ) {
  // a1 and a2 are arguments resolved for the page1 and page2 ajax requests, respectively.
  // Each argument is an array with the following structure: [ data, statusText, jqXHR ]
  var data = a1[ 0 ] + a2[ 0 ]; // a1[ 0 ] = "Whip", a2[ 0 ] = " It"
  if ( /Whip It/.test( data ) ) {
    alert( "We got what we came for!" );
  }
});
Jako Basson
  • 1,461
  • 12
  • 19
  • `$.when` takes promises as its arguments, right? I need to resolve a promise, then use data from that resolution to resolve another promise. I can't quite understand how to set up the $.when method in this scenario – Bryce Feb 19 '20 at 21:02
  • Using $.when will require you to refactor your logic quite a bit. If you want a quick win, you might want to consider running your ajax requests synchronously, e.g. set the async property to false on your $.ajax. This will force your ajax requests in the loop to wait for a result before iterating over to the next item which should yield the result you are looking for. – Jako Basson Feb 20 '20 at 17:44
  • There's a few too many calls for that unfortunately. There ended up being changes to the database that makes this moot, but in case anyone stumbles upon this, I think creating an array of promises and then checking them with Promises.all() would be the way to go. – Bryce Feb 20 '20 at 22:11