jQuery Ajax嵌套回调

I have nested callabcks but resulted output is not ordered correctly. My ajax results are in ascending orders of id but html generated is random. can someone help me out pls?

var formatedhtml = '';
$.ajax({
    type: "POST",
    url: BASE_URL + 'index.php/orders/read',
    dataType: 'json',
    success: function(data) {

        $.each(data, function(key, value) {

            console.log(value);
            getdetails(value['id'], function(output) {
                formatedhtml = formatedhtml +
                    '<div class="col-md-4 col-sm-4 col-lg-3 col-xs-6">' +
                    ' <div class="row">' +
                    ' <div class="orderno">' + value['id'] + '</div>' +
                    '<div class="tableno">' + value['tableno'] + '</div>' +
                    '<div class="ordertype">' + value['type'] + '</div>' +
                    '<div class="timestamp">' + value['created'] + '</div>' +
                    ' </div>' +
                    '<hr>';
                $.each(JSON.parse(output['items']), function(k, val) {
                    formatedhtml = formatedhtml + '<div class="row">' +
                        '<div class="quantity">' + val[3] + '</div>' +
                        '<div class="item">' + '</div>' +
                        '</div>';

                });
                formatedhtml = formatedhtml +
                    '<div class="row">' +
                    '<div class="notes">' + value['id'] + '</div>' +
                    '</div>' +
                    '</div>';
                $("#orderlist").html(formatedhtml);
                console.log(output);
            });

        });

    }
});

edit:

Here is getdetails function. its an ajax request.

function getdetails(id, callback) {
    var result;
    $.ajax({
        type: "POST",
        url: BASE_URL + 'index.php/orders/readdetails',
        dataType: 'json',
        data: {
            id: id,
        },
        success: function(data) {
            callback(data[0]);
        }
    });
};

Use async:false in your getDetails() ajax call.

function getdetails(id, callback) {
var result;
$.ajax({
    type: "POST",
    url: BASE_URL + 'index.php/orders/readdetails',
    dataType: 'json',
    async: false,
    data: {
        id: id,
    },
    success: function (data) {
        callback(data[0]);


    }
});

There are a lot of ways to achieve this, one is to use a promise and sort by id when all requests are done. Another you could create the template and append the details on callback as each detail request has an id you can define in your template a class like 'id-'+value['id'] and use jquery selector and append detail template.

Another solution would be to create a function loop that calls itself untill orderCount == orderLoaded.

Job is done synchronously (takes more time)

//Mock ajax function
$.ajax = function (param) {
    if(param.url.indexOf('readdetails') != -1){
    param.success(itemsData);
    } else {
      param.success(ordersData);
   }
};

//Mock data
var ordersData = [
  { id : 1, tableno : 'xyz', type: 'invoice', created: '01/01/2001' },
  { id : 2, tableno : 'xyz', type: 'invoice', created: '01/01/2001' },
  { id : 3, tableno : 'xyz', type: 'invoice', created: '01/01/2001' }
];

var itemsData = [
  { id : 1, orderid: 1, quantity: 5  },
  { id : 2, orderid: 1, quantity: 2  },
  { id : 3, orderid: 1, quantity: 1  }
];

// Globals
var formatedhtml = [];
var orders = [];
var lastOrderLoaded = 0;
var BASE_URL = 'localhost/';

function tpl(order, items) {
    var html = '<tr class="col-md-4 col-sm-4 col-lg-3 col-xs-6">' +
        
        ' <td class="orderno">' + order['id'] + '</td>' +
        '<td class="tableno">' + order['tableno'] + '</td>' +
        '<td class="ordertype">' + order['type'] + '</td>' +
        '<td class="timestamp">' + order['created'] + '</td>' +
        ' </tr>';

    $.each(items, function(key, item) {
      html += '<tr class="row">' +
        '<td class="item">item: ' + item.id + '</td>' +
        '<td class="quantity">quantity: ' + item.quantity + '</td>' +
        '</tr>';
    });

    html +=
      '<tr class="row">' +
      '<td class="notes"> notes </td>' +
      '<td class="notes"> order id ' + order['id'] + '</td>' +
      '</tr>' +
      '</tr>';

    formatedhtml.push({ id: order.id, html : html });
}

$.ajax({
    type: "POST",
    url: BASE_URL + 'index.php/orders/read',
    dataType: 'json',
    success: function(data) {
        lastOrderLoaded = 0;
        orders = data;
        getdetails(orders[0]);
      }
    
});


function getdetails(order) {
    $.ajax({
        type: "POST",
        url: BASE_URL + 'index.php/orders/readdetails',
        dataType: 'json',
        data: {
            id: order.id,
        },
        success: function(data) {
           tpl(order, data);
          
           if(lastOrderLoaded < orders.length - 1){
              lastOrderLoaded++;
              getdetails(orders[lastOrderLoaded]);
          } else {
            formatedhtml.forEach(function(element){
               $("#orderlist").append(element.html);
             }); // end each
          }
        }
    });
};
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="orderlist" border="1">
  <tr><th>id</th><th>no</th><th>type</th><th>date</th></tr>
</table>

Promise Solution: Job is done asynchronously (might take less time also bombards the server with many requests at once)

var formatedhtml = [];

function tpl(order, items) {
    var html = '<div class="col-md-4 col-sm-4 col-lg-3 col-xs-6">' +
        ' <div class="row">' +
        ' <div class="orderno">' + order['id'] + '</div>' +
        '<div class="tableno">' + order['tableno'] + '</div>' +
        '<div class="ordertype">' + order['type'] + '</div>' +
        '<div class="timestamp">' + order['created'] + '</div>' +
        ' </div>' +
        '<hr>';

    $.each(JSON.parse(items['items']), function(key, item) {
      var html += '<div class="row">' +
        '<div class="quantity">' + item[3] + '</div>' +
        '<div class="item">' + '</div>' +
        '</div>';
    });

    html +=
      '<div class="row">' +
      '<div class="notes">' + order['id'] + '</div>' +
      '</div>' +
      '</div>';

    formatedhtml.push({ id: order.id, html : html });
}

$.ajax({
    type: "POST",
    url: BASE_URL + 'index.php/orders/read',
    dataType: 'json',
    success: function(data) {

        var syncLoad = [];

        $.each(data, function(key, value) {
            syncLoad.push(getdetails(value, tpl));            
        });

        $.when.apply($, syncLoad).done(function() {

          formatedhtml.sort(function(a, b){
                        return a.id - b.id;
          });

          formatedhtml.forEach(function(element){
            $("#orderlist").append(element.html);
          });

      });
    }
});


function getdetails(order, callback) {
    return $.ajax({
        type: "POST",
        url: BASE_URL + 'index.php/orders/readdetails',
        dataType: 'json',
        data: {
            id: order.id,
        },
        success: function(data) {
            callback(order, data[0]);
        }
    });
};
</div>