how to concatenate an object in asynchronous function?

2
Hello, I'm developing a website to train a bit of js, but I came across the following situation: I have a javascript Object that I created to facilitate Ajax queries, however when I'm doing the requests sometimes a link is solved or finished (I do not know the right technical terminology) before the other, so this buga my site sometimes not showing the values I want (I'm using the push array method per hour), then I thought about creating a new Object while I make the requisitions with the name of each item, to get the values easily and do not have problems as the speed of the resolution of the links, however when I perform my function only returns the value of the last name of the created object.

for a better example:

Object:

ExchangeInfo = {
  mercadobitcoin:{
    name:"mercadobitcoin",
    bch:{
      orderbook:"https://www.mercadobitcoin.net/api/BCH/orderbook/"
    }
  },
  braziliex:{
    name:"braziliex",
    bch:{
      orderbook:"https://braziliex.com/api/v1/public/orderbook/bch_brl"
    }
  },
  negociecoins:{
    name:"negociecoins",
    bch:{
      orderbook:"https://broker.negociecoins.com.br/api/v3/bchbrl/orderbook"
    }
  }
};

Function:

v = {};
function getApiLinks() {
  for (prop in ExchangeInfo){
    var xml = new XMLHttpRequest();
    xml.open("GET",ExchangeInfo[prop]["bch"]["orderbook"],true);
    xml.send();
    xml.onreadystatechange = function(){
      if(this.status == 200 && this.readyState == 4){
        myObj = JSON.parse(this.responseText);
        v[ExchangeInfo[prop]["name"]]=this.responseText;
        return v[ExchangeInfo[prop]["name"]] = myObj; // resolução parcial que só retorna o ultimo valor consultado exemplo abaixo.
        // return v.push(myObj); resolução atual intermitente
      }
    }
  }
}

object returned:

{
  negociecoins:{
    ask[
      //dados retornados pelo ajax
    ],
    bid:[
      //dados retornados pelo ajax
    ]
  }
}

Expected Object:

{
  mercadobitcoin:{
    ask[
      //dados retornados pelo ajax
    ],
    bid:[
      //dados retornados pelo ajax
    ]
  },
  braziliex:{
    ask[
      //dados retornados pelo ajax
    ],
    bid:[
      //dados retornados pelo ajax
    ]
  },
  negociecoins:{
    ask[
      //dados retornados pelo ajax
    ],
    bid:[
      //dados retornados pelo ajax
    ]
  }
}

Sorry if the question was too long, I tried to give as much information as possible.

    
asked by anonymous 21.07.2018 / 18:45

1 answer

1

You can not do this this way because for is asynchronous to Ajax and will return the last processing inside it.

The return used will also return undefined because for will finish before the first request (of the total of 3) of Ajax is processed, precisely because it is asynchronous.

To get the desired result, you would have to do this synchronously, calling each Ajax request at a time, without using the for loop to make requests. You can do this using a function as shown below:

v = {};
function getApiLinks() {
   var array = []; // array para guardar os nomes dos objetos
   for (prop in ExchangeInfo){
      // adicionar os nomes dos objetos para usar no Ajax
      array.push(ExchangeInfo[prop]["name"]);
   }
   // variável que irá contar quantas vezes
   // a função será chamada
   var conta = 0;

   function Ajax(){
      var xml = new XMLHttpRequest();
      xml.open("GET",ExchangeInfo[array[conta]]["bch"]["orderbook"],true);
      xml.send();
      xml.onreadystatechange = function(){
         if(this.status == 200 && this.readyState == 4){
            myObj = JSON.parse(this.responseText);
            //v[ExchangeInfo[prop]["name"]]=this.responseText;
            v[array[conta]] = myObj; // resolução parcial que só retorna o ultimo valor consultado exemplo abaixo.
            // return v.push(myObj); resolução atual intermitente
            conta++;
            // chama novamente a função
            // até que "conta" seja menor que
            // o númrero de itens na array
            if(conta < array.length) Ajax();
         }
      }
   }
   Ajax(); // chama a função

  return v; // retorna o objeto
}

console.log(getApiLinks());

The return v; will return:

braziliex:
{asks: Array(203), bids: Array(32)}

mercadobitcoin:
{asks: Array(1000), bids: Array(247)}

negociecoins:
{ask: Array(162), bid: Array(51)}
    
21.07.2018 / 23:30