Martin Carre
Martin Carre

Reputation: 1239

How to handle Promise.all properly: Getting undefined

I'm trying to get an array filled with the info back from some requests made to different REST APIs. I thought about using Promise.all to do that but for some reason, it yields an Array with a bunch of undefined inside.

[ undefined, undefined, undefined, undefined ]

Here's my code:

var _ = require("lodash");//Used exclusively to check if the result from the request is an object
var ccxt = require("ccxt");//External library used to make the requests

let pairs = ["ETH/EUR", "BTC/EUR", "LTC/EUR", "BCH/EUR"]; //Array on which the Promise.all is based

function test(p) {
  for (var i = 0; i < ccxt.exchanges.length; i++) { //Looping through all the rest APIs
    let exchange = new ccxt[ccxt.exchanges[i]](); //Defining each API to make the requests
    if (exchange.hasFetchOrderBook) {
      exchange //Beginning of the request
        .fetchOrderBook(p)
        .then(order => {
          if (_.isObject(order) && order.bids[0][1]) {
            let now = Math.floor(new Date());
            order.mkt = exchange.name;
            order.pair = p;
            order.ping = now - order.timestamp;
            return order; //Return the result of the request
          }
        })
        .catch(e => {});
    }
  }
}

Promise.all(pairs.map(test)) //Making the requests based on the Pairs Array
  .then(res => {
    console.log(res); //Logging the results ==> [undefined, undefined, undefined, undefined] for some reason...
  })
  .catch(e => {
    console.log(e);
  });

I know that the requests are correctly being made since if I console.log the order within the loop, I get the correct results -- Example of the result when logging:

{ bids: 
   [ [ 12009.52, 0.0468 ],
     [ 12008.5, 0.0227 ],
     [ 12007.48, 30.9321 ],
     [ 12006.46, 0.0537 ],
     [ 12005.45, 0.0157 ],
     [ 12004.43, 7.1659 ],
     [ 12003.41, 0.0164 ],
     [ 12002.39, 23.4159 ],
     [ 12001.38, 0.0284 ],
     [ 12000.36, 0.0132 ],
     [ 11999.34, 0.0194 ],
     [ 11998.33, 0.0034 ],
     [ 11997.31, 7.526 ],
     [ 2445.72, 34.075 ],
     [ 2445.17, 25.4842 ],
     [ 2444.96, 0.1118 ],
     [ 2444.75, 23.288 ],
     [ 2444, 0.0247 ],
     [ 2443.8, 0.192 ],
     [ 765.51, 0.0828 ] ],
  asks: 
   [ [ 12048.74, 2.523 ],
     [ 12049.77, 0.0159 ],
     [ 12050.79, 0.029 ],
     [ 12051.82, 0.0061 ],
     [ 12052.84, 0.0181 ],
     [ 12053.87, 0.0164 ],
     [ 12054.89, 0.0355 ],
     [ 12055.92, 0.0042 ],
     [ 13419.62, 0.0063 ],
     [ 13420.64, 0.0174 ],
     [ 13421.78, 0.0143 ],
     [ 13422.92, 0.026 ],
     [ 13424.06, 0.0055 ],
     [ 13425.2, 14.4552 ],
     [ 13426.23, 0.0065 ],
     [ 13427.25, 0.0057 ],
     [ 13428.39, 0.0147 ],
     [ 13429.53, 4.0375 ],
     [ 13430.56, 23.9541 ],
     [ 13431.58, 0.0137 ] ],
  timestamp: 1512845715447,
  datetime: '2017-12-09T18:55:15.447Z',
  mkt: 'LakeBTC',
  pair: 'BTC/EUR',
  ping: 0 }

So I guess that the problems I'm dealing with has to do with the asynchronous character of the function... but I'm not sure how I can make it synchronous. Again, just to try to clarify my question: The objective is to get an array with 4 different types of object (one per pair --> array) so that I can operate on each. Just to make it clearer, here's an illustration of what I'm trying to achieve:

[
  [
    Object1,
    Object2,
    Object3,
    etc...
  ],
  [
    Object1,
    Object2,
    Object3,
    etc...
  ],
  [
    Object1,
    Object2,
    Object3,
    etc...
  ],
  [
    Object1,
    Object2,
    Object3,
    etc...
  ]
]

Why is Promise.all returning the array without waiting on the requests'results?

I hope that was clear enough! If not let mw know! :P

Thanks in advance for your help!

Upvotes: 1

Views: 59

Answers (1)

Bergi
Bergi

Reputation: 664484

Your test function does return a undefined. You need to return a promise for the result:

function test(p) {
  return Promise.all(ccxt.exchanges.map(api => { //Looping through all the rest APIs
//^^^^^^^^^^^^^^^^^^
    let exchange = new ccxt[api](); //Defining each API to make the requests
    if (exchange.hasFetchOrderBook) {
      return exchange //Beginning of the request
        .fetchOrderBook(p)
        .then(order => {
          if (_.isObject(order) && order.bids[0][1]) {
            let now = Math.floor(new Date());
            order.mkt = exchange.name;
            order.pair = p;
            order.ping = now - order.timestamp;
            return order; //Return the result of the request
          }
          // else undefined
        })
        .catch(e => {}); // undefined
    }
    // else undefined
  }));
}

Of course your promises still fulfill with undefined when the if conditions do not apply or an error happens.

Upvotes: 2

Related Questions