Home > Back-end >  Why on printing I get value of null from API call in Loop
Why on printing I get value of null from API call in Loop

Time:04-16

COIN LIST is an array of crypto coins(["BTCUSDT",...]). I try to get the price using getPriceAction and RSI from getRSI and these two functions are working when I try to console DATA. But when I try to print the response after the completion of the loop. It prints the empty array and the length is 0 of this array. I want to store the DATA object (consisting of SYMBOL, closing price and RSI) as an element in the response array

 import { COIN_LIST } from "./COIN_LIST.js";
    import { getPriceAction } from "./PRICE_ACTION.js";
    import { getRSI } from "./RSI.js";

async function main() {
  try {
    let response = await [];
    await COIN_LIST.forEach((element, i) => {
      setTimeout(() => {
        let data = { symbol: element };
        getPriceAction(element, "4h").then((res) => {
          data.closingPrice = res;
          getRSI(res).then((res) => {
            data.RSI = res.reverse();
            data.closingPrice = data.closingPrice.reverse();
            response.push(data);
            console.log(data)
          });
        });
      }, i * 1000);
    });
    console.log(response);
  } catch (error) {
    console.log(error.message);
  }
}
main();

CodePudding user response:

If you want to use async/await properly for your code, then use async/await, don't use .then/.catch as well

Some notable changes

there is no setTimeout of increasing seconds ... just waiting 1 second after one result before getting the next - far cleaner, and if one request happens to take a lot longer, you won't end up with two requests at once (which may be an issue if the API is rate limited)

no .then ... use async/await OR .then/.catch - very rare to need both in the one function

don't use forEach with async/await ... it never does what you want, and creating an array of Promises inside a .forEach is extremely naive, you may as well use .map instead! then you can await Promise.all(xxx.map(.....)) - but that's useful for concurrent requests, not so much for serial requests like your code does

import { COIN_LIST } from "./COIN_LIST.js";
import { getPriceAction } from "./PRICE_ACTION.js";
import { getRSI } from "./RSI.js";

async function main() {
    try {
        const wait = (ms) => new Promise(resolve => setTimeout(resolve, 1000));
        let response = []; //---> don't need that `await`
        for (let element of COIN_LIST) {
            let data = { symbol: element };
            data.closingPrice = await getPriceAction(element, "4h");
            const res = await getRSI(data.closingPrice);
            data.RSI = res.reverse();
            data.closingPrice = data.closingPrice.reverse();
            response.push(data);
            console.log(data);
            await wait(1000);
        }
        console.log(response);
    } catch (error) {
        console.log(error.message);
    }
}
main();

the await wait(1000) could be tweaked depending on the rate limiting of the API ... if the rate limit applies to when the request is made, you could make a function that is smart about the delay between requests.

The code this way assumes the rate limit is based on the period between previous response to next request.

CodePudding user response:

After the completion of the loop, the promises didn't get resolved yet, that's why it print an empty array. One way to achieve what you need is using await for(...), or wait for all promises to be resolved, and then print the results.

import { COIN_LIST } from "./COIN_LIST.js";
import { getPriceAction } from "./PRICE_ACTION.js";
import { getRSI } from "./RSI.js";

async function main() {
  try {
    let response = []; //---> don't need that `await`
    const promises = []; //---> array of promises
    COIN_LIST.forEach((element, i) => {
      setTimeout(() => {
        let data = { symbol: element };
        const promise = getPriceAction(element, "4h").then((res) => {
          data.closingPrice = res;
          getRSI(res).then((res) => {
            data.RSI = res.reverse();
            data.closingPrice = data.closingPrice.reverse();
            response.push(data);
            console.log(data)
          });
        });
        promises.push(promise) //---> save the reference to a promise
      }, i * 1000);
    });
    await Promise.all(promises) //---> await for all promises to be resolved, then print the result
    console.log(response);
  } catch (error) {
    console.log(error.message);
  }
}
main();
  • Related