0

I have some code

function getSomeInfoFromDB() {
    let body = "";
    let text = "";
    $("tr").each(function (index) {
        let code = $(this).children("td:nth-child(2)");
        $.post("http://urltogetdatafromdatabase.com/getinfo.php", {a: code}).done(function (data) {
            text = "<dvi>" + index + " " + data + "</div>";
        });
        body = body + text;
    });

    let bigboody = "<div class='outer'>" + body + "</div>";
    doSomethingWithResult(bigboody);
}

But doSomethingWithResult() always work before $post return me data How can I do this work fine?

In result I need

  <div class='outer'>
  <div> 1 data text from database</div>
  <div> 2 next text from database</div>
  </div>
Arafath
  • 1,090
  • 3
  • 14
  • 28
Alex Latro
  • 93
  • 1
  • 10
  • Posible duplicate : https://stackoverflow.com/questions/18983138/callback-after-all-asynchronous-foreach-callbacks-are-completed – Arafath Nov 30 '17 at 11:15

3 Answers3

0

Your done function is a call back function of post. It's called after receiving data from your server side. So, doSomethingWithResult is calling before your done function You need to call your doSomethingWithResult function in the callback

function getSomeInfoFromDB(){
    let body= "";
    let text = "";
    $("tr").each(function(index){
    let code = $(this).children("td:nth-child(2)");
    $.post( "http://urltogetdatafromdatabase.com/getinfo.php", { a: code     }).done(function( data ){
        text = "<dvi>"+index+" "+data+"</div>";
        let bigboody = "<div class='outer'>"+body+"</div>";
        doSomethingWithResult(bigboody);
    });
    body = body + text;
    });


}
Stéphane Ammar
  • 1,454
  • 10
  • 17
  • Problem is the problem is that I need in result < div.outer >< div> 1 div with text< /div>< div> 2 div with text< /div> < /div > NOT < div.outer >< div> 1 div with text< /div>< /div > < div.outer >< div> 2 div with text< /div> < /div > – Alex Latro Nov 30 '17 at 11:23
0

You'll have to move doSomethingWithResult() inside of your done() function, since post() is async.

function getSomeInfoFromDB(){
  let body= "";
  let text = "";

  $("tr").each(function(){
    let code = $(this).children("td:nth-child(2)");
    $.post( "http://urltogetdatafromdatabase.com/getinfo.php", { a: code })
      .done(function(data) {
        text = "<div>"+data+"</div>";
        body = body + text;

        let bigboody = "<div class='outer'>"+body+"</div>";
        doSomethingWithResult(bigboody);
      });
    });
}

But note that post() in an each(), they may return in different orders, which since you're appending them, may not be what you want.

The safer approach (where you can control the order), is to use Promise.all() and gather the post() calls up as promises and into an array. Something like this:

function getSomeInfoFromDB(){
  let promises = [];

  $("tr").each(function(){
    let code = $(this).children("td:nth-child(2)");
    promises.push(new Promise((resolve) => 
      $.post( "http://urltogetdatafromdatabase.com/getinfo.php", { a: code }).done(resolve)
    ))
  });

  Promise.all(promises)
    .then(datas => '<div>' + datas.join('</div><div>') + '</div>') // easy way to wrap all of them in divs and put them together
    .then(body => doSomethingWithResult('<div class="outer">' + body + '</div>');
}

Basically, you wrap each post() up as a Promise and put that Promise in an array. Then, use Promise.all() which will run when all of the promises are finished. The then() for that will give you an array of results, one for each post, in order. You can then do whatever you want with them at that point.

samanime
  • 25,408
  • 15
  • 90
  • 139
  • In this case .then(datas and .then(body new variables? – Alex Latro Nov 30 '17 at 11:48
  • Looks like promise is the best way to do this – Alex Latro Nov 30 '17 at 11:55
  • Yeah. You can do it in one `.then()`, but I think it's cleaner with two. The first gets an array of the results of all of your posts (each element is one result). Joining that into a string gives the equivalent of your `body`. If you return that from the first then, it'll be the input for the second then, giving you a fairly clean look. – samanime Nov 30 '17 at 12:05
0

If you need all data to be executed in that order, your already have other answers.

If you don't care abour order, but must wait until all is done, you can count calls and wait until last one is done, like this

function getSomeInfoFromDB()
{
    let body = "";
    let text = "";
    var waiting=0;

    $("tr").each(function (index) {
        let code = $(this).children("td:nth-child(2)");
        waiting++;
        $.post("http://urltogetdatafromdatabase.com/getinfo.php", {a: code}).done(function (data) {
            text = "<dvi>" + index + " " + data + "</div>";
            waiting--;
            if (waiting==0)
            {
                let bigboody = "<div class='outer'>" + body + "</div>";
                doSomethingWithResult(bigboody);
            }

        });
        body = body + text;
    });
}
MatKus
  • 56
  • 11