async api call function seems to work until test - javascript

I am trying to get some exchange data and use it for some logic. I thought the most straight forward idea would be to use a function where I could pass the different pairs I may want, there are many per exchange. If I console log inside the function when the data ends everything works find. When i try and get the response when it is ready I get undefined, please see the commented console log and my last line.
I understand that I am missing something with async and the way it works.
const https = require('https');
async function binancePairPrice (binancePair) {
let url = 'https://api.binance.com/api/v3/ticker/bookTicker';
let queryString = '?symbol='
https.get(url+queryString+binancePair,(res) => {
console.log(res.statusCode);
let binanceBookTicker = '';
let binanceBookTickerJson =
res.on('data', data => {
binanceBookTicker += data;
});
res.on('end', () => {
binanceBookTickerJson = JSON.parse(binanceBookTicker);
//console.log(binanceBookTickerJson);
return (binanceBookTickerJson)
});
});
};
binancePairPrice('BTCUSDT').then(console.log);
day one javascript coming from python. This is quite a step from what I am used to writing. Any docs or links would be appreciated too.
thansk

https.get doesn't return something that can be promisified, so you can't await it.
You can do something else which is wrapping the https.get call within a Promise and then await it when calling binancePairPrice.
const https = require('https')
async function binancePairPrice (binancePair) {
let url = 'https://api.binance.com/api/v3/ticker/bookTicker';
let queryString = '?symbol='
return new Promise((resolve) => {
https.get(url, res => {
let binanceBookTicker = '';
let binanceBookTickerJson =
res.on('data', data => {
binanceBookTicker += data;
});
res.on('end', () => {
resolve() = >
{
binanceBookTickerJson = JSON.parse(binanceBookTicker);
return (binanceBookTickerJson)
}
});
})
})
}
(async () => await binancePairPrice('BTCUSDT))()

Your binancePairPrice function doesn't wait for the end callback to happen and therefore just carries on and returns undefined.
You need to return a Promise and then resolve the promise with the value you want to return from the function.
Promise basics
Using the Promise() constructor
async function binancePairPrice (binancePair) {
return new Promise((resolve, reject) => {
let url = 'https://api.binance.com/api/v3/ticker/bookTicker';
let queryString = '?symbol=';
https.get(url+queryString+binancePair,(res) => {
console.log(res.statusCode);
let binanceBookTicker = '';
let binanceBookTickerJson =
res.on('data', data => {
binanceBookTicker += data;
});
res.on('end', () => {
binanceBookTickerJson = JSON.parse(binanceBookTicker);
//console.log(binanceBookTickerJson);
resolve(binanceBookTickerJson)
});
});
});
}

Related

Logging Function results from an API call - Javascript

I've written a function that makes an API call using AWS lambda and then logs the function result to Splunk. My issue is that for some reason the result is not being logged. I think it needs to be converted to an async function, but I'm struggling to convert it being a JS newbie. Thanks in advance for the help.
const detailedNotification = function() {
https.get(newUrl, options, (res) => {
let body = "";
res.on("data", (chunk) => {
body += chunk;
const result = JSON.parse(body);
console.log(result);
});
res.on("end", () => {
let json = JSON.parse(body);
let output = json.items;
//console.log(output);
});
}).on("error", (error) => {
console.error(error.message);
});
};
detailedNotification();

How to change variable value in Axios response?

I'm trying to change a variable value in axios's then. Here is my example:
var pts = [];
axios.get('http://www.example.com')
.then(function (response) {
pts = response.data;
});
console.log(pts);
The pts variable just returns empty array. I just want to use it out of the GET query. How can I change it?
use the new elegant way async & await it is more neat and readable
let pts = [];
const getData = async () => {
const {data} = await axios.get("http://www.example.com");
pts = data;
return data
}
getData();
console.log(pts);
The request is asynchronous so the pts gets printed first and then the function gets called
What you can do is use a promise and make your request as follows:
const func1 = () => {
return axios.get("http://www.example.com").then(response => {return response})
}
func1().then(data => {
pts = data;
})

What are different ways to handle asynchronous calls (apis) inside a for loop or array method?

I have been trying to create an api like this where I tried different things like using array methods like map/filter/reduce where either I get pending promises or result returned before execution of api call.
So my doubt is -->
How do I get total number of drawn matches of all pages ( so I need to add data.total from all pages).
How to better understand this behaviour.
async function getNumDraws(year) {
const goals = [...Array(11).keys()];
let result = 0;
console.log(`before loop ${new Date()}`);
for(let goal of goals){
console.log(`in loop before await ${new Date()}`);
await require('https').get(`https://jsonmock.hackerrank.com/api/football_matches?year=${year}&team1goals=${goal}&team2goals=${goal}`,res=>{
let data="";
res.on('data', (chunk) => {
data += chunk;
});
// The whole res has been received. Print out the result.
res.on('end', () => {
data=JSON.parse(data);
console.log(result,data.total)
result= result + data.total;
});
})
console.log(`in loop after await ${new Date()}`);
}
console.log(`after loop ${new Date()}`);
return result;
}
console.log(getNumDraws(2011));
https.get is a callbacked function so await won't work. You should promisify it first like they did in this other SO question;
const https = require("https"); // only require this once
const getJSONAsync = url => new Promise((resolve, reject) => { // define a function getJSONAsync which returns a Promise that wraps the https.get call, getJSONAsync is awaitable
let req = https.get(url, res => { // make the https.get request
if(res.statusCode < 200 || res.statusCode >= 300) { // if the status code is an error one
return reject(new Error('statusCode=' + res.statusCode)); // reject and skip the rest
}
let body = []; // otherwise accumulate..
res.on('data', chunk => body.push(chunk)); // ..the data
res.on('end', () => { // on end
try {
body = JSON.parse(Buffer.concat(body).toString()); // try to JSON.parse the data
} catch(e) {
reject(e); // reject if an error occurs
}
resolve(body); // resolve the parsed json object otherwise
});
});
req.on("error", error => reject(error)); // reject if the request fails too (if something went wrong before the request is sent for example)
});
async function getNumDraws(year) {
let result = 0;
for(let goal = 0; goal < 11; goal++) {
let data = await getJSONAsync(`https://jsonmock.hackerrank.com/api/football_matches?year=${year}&team1goals=${goal}&team2goals=${goal}`);
result += data.total;
}
return result;
}
Note: getJSONAsync is not specific to getNumDraws, you can use it somewhere else if you need it, and since it returns a Promise you can either await it like getNumDraws does or use it with then/catch blocks like so:
getJSONAsync("url")
.then(data => {
// data is the parsed json returned by the request
})
.catch(error => {
// the error message if something fails
})

Using Async Values in another function (JavaScript)

I am currently working with destructuring arrays in Javascript, I would like to access these variables in other functions but currently, I am struggling to figure out how I might go about this.
I've tried calling the function and then console.log(thermostatArray) -> I believe this returned pending promise
I've tried calling the function and awaiting it and then console.log thermostatArray.
dataFormat() is properly able to see log and use the array but heatCallCheck() is not and I am not seeing past the issue yet.
var express = require("express");
var router = express.Router();
const multer = require("multer");
var Excel = require("exceljs");
const index = require("../routes/index");
const workbook = new Excel.Workbook();
async function convertFile(workbook) {
csvWorkbook = workbook.csv.readFile("./uploads/uploadedFile.csv");
await csvWorkbook.then(async function(csvWorkbook) {
const worksheet = workbook.getWorksheet("sheet1");
try {
// await dataFormat(worksheet);
await heatCallCheck(worksheet,)
} catch (err) {
console.log(err);
}
await workbook.xlsx.writeFile("./uploads/convertedFile.xlsx").then(() => {
console.log("converted file written");
});
});
}
async function dataFormat(worksheet) {
let thermostatArray = []
await csvWorkbook.then(async function(worksheet) {
const serialNum = worksheet.getCell("D1").value;
const thermostatName = worksheet.getCell("D2").value;
const startDate = worksheet.getCell("D3").value;
const endDate = worksheet.getCell("D4").value;
const thermostat = worksheet.eachRow({includeEmpty: true}, function(row,rowNumber){
if (rowNumber > 6) {
thermostatArray.push(row.values)
}
})
console.log(`${thermostatArray[5]} Array Sample from dataFormat` )
console.log(`${thermostatArray[6]} Array Sample from dataFormat` )
return thermostatArray
})}
async function heatCallCheck(worksheet,thermostatArray) {
let test = await dataFormat(worksheet).then(thermostatArray => {
return thermostatArray[5]
}).catch(err => {
console.error(err)
})
console.log(`${test} result `)
}
My expected results, in this case, would be that I would be able to see the 4th element in thermostat array using the heatCallCheck() function.
I figured I would be able to access it after the .then is called.
my understanding is that .then(thermostatArray =>
makes that array the return value.
You do this:
async function someFunction() {
const myResultFromAPromise = await functionThatReturnsAPromise();
// ....do some stuff
return myResultFromAPromise;
}
OR
function someFunction() {
return functionThatReturnsAPromise().then(function(myResultFromAPromise) {
// ...do some stuff
return myResultFromAPromise;
});
}
but don't do both, it's just terribly confusing.
EDIT: as a commenter pointed out, you can await anything, but it's clear from your code that you're very confused about the point of async/await

What's wrong with this async function?

async lsEntered(){
if(this.service.wd == '')
{
await basic((this.service.wd));
}
else
{
await basic(('/'+this.service.wd));
}
this.files = await JSON.parse(localStorage.getItem('FILENAMES'));
var filesList = document.getElementById(this.trackLine.toString());
var li;
for (var i = 0; i < this.files.length; i++) {
li = document.createElement('li');
li.appendChild(document.createTextNode(this.files[i].name));
filesList.appendChild(li);
}
localStorage.clear();
}
I want to wait until basic is finished and JSON.parse finishes before displaying the values in the DOM. I'm getting the values of the previous call every time which is tell me the async is no working. To be fair I don't have tons of TS experience.
Edit: This is basic I was hoping not to have to deal with it as it's a javascript function and fragily integrated into this app.
var basic = function (path) {
var ACCESS_TOKEN = '';
var dbx = new Dropbox({ accessToken: ACCESS_TOKEN });
dbx.filesListFolder({ path: path })
.then(function (response) {
localStorage.setItem('FILENAMES',JSON.stringify(response.entries));
console.log(response);
})
.catch(function (error) {
console.error(error);
});
return false;
}
let myPromise = new Promise((resolve, reject) => {
// Work you want to execute
resolve("I am done");
});
myPromise.then((successMessage) => {
// successMessage is whatever we passed in the resolve(...) function above.
console.log("Yay! " + successMessage);
});
You can only await promises1 and basic is not returning a promise. You need to do
return dbx.filesListfolder(...)...
Also consider what Bergi said in their comment.
1: Actually, you can await any value, but there is no point in awaiting something that is not a promise. By not returning the promise from basic, lsEntered won't wait for the local storage to be set.

Categories