1

I have a Javascript for loop which runs through an array of database records (that have been extracted already).

I want to know when all the subsequent asynchronous actions have completed but I can't seem to do it.

For each record, the code runs a number of functions which return promises and then resolve (which then triggers another function to get more information, etc). This all works ok, but I can't figure out how to gather up each "FOR" iteration and detect when all records have been processed. Basically, I want to use a "throbber" and have the throbber remain until all processing has been completed.

Code is below (I've removed some extraneous info)...

for (var i = 0; i < systemArray.length; i++) {
    // ***** FOR EACH SYSTEM ***** //

    var currRecord = systemArray[i];

// SECTION REMOVED //

    // GET SYSTEM LINES
    var thisSystem = AVMI_filterArray("8.9", currRecord);
    var thisSystemName = thisSystem[1].value;
    var thisSystemRID = thisSystem[0].value;

    // GET CHILDREN RIDS
    AVMI_getChildren(systemLinesTable, thisSystemRID, systemLinesFID).done(function(ridList, sysRID)
        {
            var thisDiv = "div#" + sysRID;
            // GET RECORD INFO FOR EACH RID
            AVMI_getMultipleRecordInfoFromArray(ridList, systemLinesTable).done(function(systemLinesArray)
                {
                    if (systemLinesArray != "" && systemLinesArray != null) {
                        systemLinesArray = systemLinesArray.sort(propComparator("10"));
                        x = AVMI_tableCombiner("System Lines", systemLinesArray, systemLinesCLIST, "skip3Right hbars xsmallText");
                        $(thisDiv).append(x);
                    } else {
                        $(thisDiv).append("<p>No System Lines...</p>");
                    }
                }
            );
        }
    );
} // ***** FOR EACH SYSTEM ***** //
AVMI_throbberClose(); // THIS, OF COURSE, EXECUTES ALMOST IMMEDIATELY

Here is function 1

///////////////////////////////////////////////////////////////
// Get related records using master
///////////////////////////////////////////////////////////////

function AVMI_getChildren(AVMI_db, AVMI_rid, AVMI_fid, AVMI_recText) {

    var AVMI_query = "{" + AVMI_fid + ". EX. " + AVMI_rid + "}";
    var AVMI_ridList = [];
    var dfd2 = $.Deferred();

    $.get(AVMI_db, {
        act: "API_DoQuery",
        query: AVMI_query,
        clist: "3",
        includeRids: "1"
    }).then(function(xml1) {
        $(xml1).find('record').each(function(){
            var AVMI_record = $(this);
            var AVMI_childRID = AVMI_record.attr("rid");
            AVMI_ridList.push(AVMI_childRID);
        });
    AVMI_throbberUpdate("Found " + AVMI_ridList.length + " " + AVMI_recText + "...");
    dfd2.resolve(AVMI_ridList, AVMI_rid);
    });
    return dfd2.promise();
};

And function 2

///////////////////////////////////////////////////////////////
// Get record info for each array member
///////////////////////////////////////////////////////////////

function AVMI_getMultipleRecordInfoFromArray(ridList, AVMI_db, AVMI_recType) {
    var promises = [];
    var bigArray = [];
    $.each(ridList, function (index,value) {
        var def = new $.Deferred();
        var thisArray = [];

        $.get(AVMI_db, {   //******* ITERATIVE AJAX CALL *******
            act: 'API_GetRecordInfo',
            rid: value
        }).then(function(xml2) {
            AVMI_throbberUpdate("Got " + AVMI_recType + " " + value + "...");
            $(xml2).find('field').each(function() {
                var $field = {};
                $field.fid = $(this).find('fid').text();
                $field.name = $(this).find('name').text();
                $field.value = $(this).find('value').text();
                thisArray.push($field);
            });
            thisArray = thisArray.sort(AVMI_ArrayComparator);
            bigArray.push(thisArray);
            def.resolve(bigArray);
        });
        promises.push(def);
    });
    return $.when.apply(undefined, promises).promise();
};

Any ideas of how to structure this? I've tried all sorts of things with $.Deferred but I can't quite figure it out...

  • You are looking for something like [`Promise.all()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all) which waits for all promises to resolve or rejects if one of the promises rejects. – Christoph Feb 28 '17 at 18:07

2 Answers2

1

You do exactly the same thing you did in AVMI_getMultipleRecordInfoFromArray: Collect the promises in an array and use $.when (or Promise.all) to wait until they are resolved.

You can simply use .map in here which also takes care of the "function in a loop" problem:

var promises = systemArray.map(function(currRecord) {
   // ...
   return AVMI_getChildren(...).done(...);
});

$.when.apply(undefined, promises).done(function() {
  AVMI_throbberClose();
});
Community
  • 1
  • 1
Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
-1

You should have to disable the async property of ajax. By default it is set to true. It means that your doesn't wait for your ajax response. That why it is returning you undefined value and you have to set it to false. So your code will wait your request to complete.

So all you have to do is.

$.ajax({
  url: '',
  type: '',
  async: false,
  success: function(data){
  }
});
Sudhanshu Jain
  • 494
  • 3
  • 11
  • that's a bad idea. Do you want to freeze the UI? The right way is to go with deferred objects/promises. – Christoph Feb 28 '17 at 18:05