Search code examples
javascriptjqueryajax

JavaScript nested AJAX calls and promises how to chain correctly?


I am stuck at setting the proper order of execution for following. Suppose, i need to make an AJAX call, then process the data and store it in IndexedDB. I use idb-keyval lib for that, which operated on promises. Then, based on the data content, i need to make another AJAX call to get some dependent data and also store it in IndexedDB. Then, i have to trigger final data processing for the document. For that I try to use ajaxStop event, which would trigger when all AJAX calls are completed. However, the order of the processing is not as expected. The ajaxStop event fires when the main AJAX call is finished without waiting for the child call to complete. Then, it fires again when sub-call is completed.

Here is my code:

import { set } from 'https://cdn.jsdelivr.net/npm/idb-keyval@6/+esm';

$(document).on("ajaxStop", function() {
    console.log("All Done!");
});

$(document).ready(function () {
    $.ajax({
      url: '/echo/json/',
      async: true,
      beforeSend: function(){
        console.log("Sending main request!");
      },
      success: function () {
        set('test', 'test').then(() => {
            $.ajax({
              url: '/echo/json/',
              async: true,
              beforeSend: function(){
                console.log("Sending sub-request!");
              },
              success: function() {
                set('sub-test', 'sub-test');
                console.log("Sub-request done!");
              }
          });
        });
      }
    });
});

what i see in console is following:

enter image description here

What am I missing to make ajaxStop wait for all calls to complete? Or, how to make the main AJAX call to wait for success function to process all the data and only then report completion?


Solution

  • Your code should be changed to approximately the following:

    $(document).ready(function () {
        $.ajax({
          url: '/echo/json/',
          beforeSend: function(){
            console.log("Sending main request!");
          },
        }).then(() => {
          return set('test', 'test');
        }).then(() => {
          return $.ajax({
            url: '/echo/json/',
            beforeSend: function(){
              console.log("Sending sub-request!");
            },
          });
        }).then(() => {
          console.log("Sub-request done!");
          return set('sub-test', 'sub-test');
        }).catch(console.error);
    });
    

    A few things to note:

    1. You don't need to set async to true in your $.ajax requests, that's the default
    2. Make sure you return the promises from your .then handlers to get proper timing on the chain
    3. Don't forget to attach a catch handler, even if it's just console.error as I've done here.