Get promise value inside loop - javascript

I'm a beginner in Javascript/NodeJS and I'm prefer practical work, I'm practicing by creating a bot discord with discord.js
The objective of this one is simply to display me the current value of the bitcoin in USD.
To get the value of BTC, I use the coingecko-api package.
However I'm blocked because although I can get the value of bitcoin, I can't do it when I'm in a loop without really understanding why.
main.js :
var coin = require('./coingecko');
while(true) {
coin.btc().then((value => console.log (value) )); // <= This show nothing
// Other things
...
}
coingecko.js :
const CoinGecko = require('coingecko-api');
const CoinGeckoClient = new CoinGecko();
module.exports = {
btc: async function btc() {
let btc = await CoinGeckoClient.coins.fetch('bitcoin', {});
return btc['data']['market_data']['current_price']['usd'];
}
}
Any tips ? Thank's

Put your loop into an async function. Using await rather than .then() makes your looping logic much more straightforward.
const coin = require('./coingecko');
/* declare the async function */
async function doLoop () {
while(true) {
const value = await coin.btc()
console.log(value)
// Other things
...
}
}
/* invoke the async function from non-async context */
doLoop().catch(console.error)

Are you sure about the ["data"] part?
When I test this API here I get this response: https://www.coingecko.com/en/api/documentation
"market_data": {
"current_price": {
"aed": 183098,
"ars": 5097411,
...
"uah": 1356629,
"usd": 49850,
Also you can probably just do btc.market_data.current_price.usd

Related

How to take two fetches and compare their data as variables whilst not getting any errors?

I want to take two different fetches, put them into a variable form so their important data can be used for something else other than just logging the data.
I'm trying to do this via window response async, however, I am currently at a dead end because though what I'm doing works on one strand of data, it doesn't work on two because of the JSON body stream already read error.
let RESPONSE = window.Response.prototype.json;
window.Response.prototype.json = async function () {
if (!('https://a/')) return RESPONSE.call(this)
let x = await RESPONSE.call(this);
if (!('https://b/')) return RESPONSE.call(this)
let y = await RESPONSE.call(this);
for (let detect in x) {
if (x[detect] !== y[detect]) {
console.log(x[detect]);
console.log(y[detect]);
}
}
return x;
return y;
};
How can I keep the data in a variable form that can be used for something like this:
for (let detect in x) {
if (x[detect] !== y[detect]) {
console.log(x[detect]);
console.log(y[detect]);
}
but whilst being able to have both variables defined at the same time? This would mean I would need to get past the body stream error while also keeping that core code. How can I do that?
Does this help you?
async function doTwoRequestsAndCompareStatus() {
const res1 = await fetch("https://fakejsonapi.com/fake-api/employee/api/v1/employees");
const res2 = await fetch("https://fakejsonapi.com/fake-api/employee/api/v1/employees");
const data1 = await res1.json();
const data2 = await res2.json();
console.log('both were equal?', data1.status === data2.status);
}
// Don't forget the actually call the function 😉
doTwoRequestsAndCompareStatus();
Although I would recommend this, both because it's cleaner and faster, as the fetches are executed at the same time and not sequentially.
async function doTwoRequestsAndCompareStatus() {
const [data1, data2] = await Promise.all([
fetch("https://fakejsonapi.com/fake-api/employee/api/v1/employees").then(r => r.json()),
fetch("https://fakejsonapi.com/fake-api/employee/api/v1/employees").then(r => r.json()),
]);
console.log('both were equal?', data1.status === data2.status);
}
// Don't forget the actually call the function 😉
doTwoRequestsAndCompareStatus();
If you find the first one easier to understand though, I would recommend using it 👍.

Best way to to use async/promise/callbacks in for loop [duplicate]

This question already has answers here:
How do I convert an existing callback API to promises?
(24 answers)
Closed 2 years ago.
I'm building a trading bot that needs to get stock names from separate files. But even I have used async function and await in my code, that doesn't work.
My index file init method.
const init = async () => {
const symbols = await getDownTrendingStock();
console.log("All stocks that are down: " + symbols);
const doOrder = async () => {
//do stuff
}
doOrder();
}
my getDownTrendeingStock file
const downStocks = []
function getDownTrendingStock () {
for(i = 0; i < data.USDTPairs.length; i++){
const USDTPair = data.USDTPairs[i] + "USDT";
binance.prevDay(USDTPair, (error, prevDay, symbol) => {
if(prevDay.priceChangePercent < -2){
downStocks.push(symbol)
}
});
}
return downStocks;
}
I have tried to also use async in for loop because the getDownTrendinStock function returns an empty array before for loop is finished. I didn't find the right way to do that because I was confused with all async, promise and callback stuff. What is the right statement to use in this situation?
Output:
All stocks that are down:
Wanted output:
All stocks that are down: [BTCUSDT, TRXUSDT, ATOMUSDT...]
I think the main issue in the code you posted is that you are mixing callbacks and promises.
This is what's happening in your getDownTrendingStock function:
You start iterating over the data.USDTPairs array, picking the first element
You call binance.prevDay. This does nothing yet, because its an asynchronous function that takes a bit of time. Notably, no data is added to downStocks yet.
You continue doing 1-2, still, no data is added
You return downStocks, which is still empty.
Your function is complete, you print the empty array
Now, at some point, the nodejs event loop continues and starts working on those asynchronous tasks you created earlier by calling binance.prevDay. Internally, it probably calls an API, which takes time; once that call is completed, it calls the function you provided, which pushes data to the downStocks array.
In summary, you didn't wait for the async code to complete. You can achieve this in multiple ways.
One is to wrap this in a promise and then await that promise:
const result= await new Promise((resolve, reject) => {
binance.prevDay(USDTPair, (error, prevDay, symbol) => {
if (error) {
reject(error);
} else {
resolve({prevDay, symbol});
}
});
});
if(result.prevDay.priceChangePercent < -2){
downStocks.push(result.symbol)
}
Note that you can probably also use promisify for this. Also, this means that you will wait for one request to finish before starting the next, which may slow down your code considerably, depending on how many calls you need; you may want to look into Promise.all as well.
Generally speaking, I use two technics:
const asyncFunc = () => {smthAsync};
const arrayToProcess = [];
// 1
const result = await arrayToProcess.reduce((acc, value) => acc.then(() => asyncFunc(value)), Promise.resolve(someInitialValue));
// 2
// here will be eslint errors
for(let i = 0 i < arrayToProcess.length; i+=1) {
const processResult = await asyncFunc(value);
// do with processResult what you want
};

how do I assign a returned value from an async function to a variable

I am new to JavaScript and have been trying to read up a lot on why this is not working. Here is my code. I have also read a number of articles here on stack overflow but still feeling dense
Also if my title does not make sense, please suggest an edit
listRef.listAll()
.then(response => {
let files = []
response.items.forEach(item => {
var text
getText(item.name).then(res=>{text = res});
const id = {uid: guid()}
const url = item.getDownloadURL().then(url => {return url} )
const gsurl = `gs://archivewebsite.appspot.com/${folder}/${item.name}`
files.push({...item, name:item.name, url, gsurl, id:id.uid, text})
});
this.files = files;
})
.catch(error => console.log(error));
async function getText(docID) {
var docRef = firestore.collection("recipes").doc(docID);
let doc = await docRef.get()
if (doc.exists){
return doc.data().text
}
}
that code "works" in that it logs the response to the console but the text variable is a pending promise object.
I understand that async functions return a promise so when I call getText I need to use .then - what I am struggling with and have refactored this code a few times is this:
how can I assign the value of doc.data().text to a variable to be used later in other words, how can var text be an actual string and not a promise object pending
Also for my own learning on javascript inside the async function if I replace
if (doc.exists){
return doc.data().text
}
with
if (doc.exists){
return Promise.resolve(doc.data().text)
}
I get the same result in console.log - is this expected? is return simply short hand for the handler to resolve the promise?
I have also refactored this code to be non async and I get the same result where my var text is basically a pending promise and never the resolved data
Thanks for your help - also any articles to help explain this to me would be great! I have been going through courses on udemy but little confused by this right now
Actually you are assigning the complete promise to the variable text
Replace
var text = getText(item.name).then(res=>console.log(res))
by
var text = await getText(item.name);
OR
var text
getText(item.name).then(res=>{text = res});
Of course text is going to be a Promise. Promise.then() always returns a Promise.
Consider this code:
function doA(n) {
// do something here...
console.log("A" + n);
}
asnyc function doB(n) {
// do something here...
console.log("B" + n);
}
doA(1);
doA(2);
doB(3); // async
doA(4);
doB(5); // async
doB(6); // async
doA(7);
What do you expect the output to be?
1, 2, 4, and 7 will always be in order, because they are executed synchronously.
3 will not ever print before 1 and 2. Likewise, 5 and 6 will not ever print before 1, 2, and 4.
However, 3, 5, and 6 can be printed in any order, because async functions do not guarantee execution order once created.
Also, 4 can print before 3. Likewise, 7 can print before 5 and 6.
Basically, think of async functions as a parallel task that runs independently (although not really; single thread JS only simulates this behavior). It can return (fulfill/reject) at any moment. For this reason, you cannot just simply assign a return value of an async function to a variable using synchronous code - the value is not guaranteed to be (and probably is not) available at the moment of synchronous execution.
Therefore you need to put all the code that requires the value of text to be set into the callback block of the Promise, something like this:
getText(item.name).then((text) => {
// put everything that uses text here
});
This can of course lead to the infamous "callback hell", where you have layers inside layers of async callback. See http://callbackhell.com for details and mitigation techniques.
async/await is just one of the newer ways to do the same thing: MDN has an excellent article here: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Async_await
OK I worked with someone at work and found a solution - it was related to this post
https://stackoverflow.com/a/37576787/5991792
I was using async function inside a for each loop
the refactored code is here
async function buildFiles(){
let items = await listRef.listAll()
let files = []
for (const item of item.items){
const text = await getText(item.name)
const url = await item.getDownloadURL()
const gsurl = `gs://archivewebsite.appspot.com/${folder}/${sermon.name}`
files.push({...item, name:item.name, url, gsurl, text})
}
return files
}
async function getText(docID) {
var docRef = firestore.collection("recipies").doc(docID);
let doc = await docRef.get()
if (doc.exists){return await doc.data().text}}
buildFiles().then(res=>this.files = res)
Thanks also to #cyqsimon and #Nav Kumar V

How to iterate a JSON array and add data from an async arrow function?

I'm new on MEAN stack and also on JS. What I'm trying to accomplish is to adapt the response that I get from the DB adding to it another field.
I have a mongoose method that gave me all the Courses that exist and I want to add to that information all the Inscriptions for each one. So I'm trying this:
exports.getAllCourses = async(req, res) => {
try {
const rawCourses = await Course.find();
const courses = await courseAdapter.apply(rawCourses)
await res.json({courses});
} catch (error) {
console.log(error);
res.status(500).send("Ocurrio un error imprevisto :/");
}
};
My courseAdapter
exports.apply = (courses) => {
return courses.map(async course=> (
{
...course._doc,
number: await coursetUtils.getNumberOfInscriptions(course._doc._id)
}
));
}
And my courseUtils:
exports.getNumberOfInscriptions = async courseId => {
return await CourseInscription.countDocuments({courseId: courseId});
}
I think my problem is with the async-await function because with this code i get this:
{"courses":[
{},
{}
]}
or changing some stuff i get this:
{"courses":[
{"courseInfo":{...},
"number":{}
},
{"courseInfo":{...},
"number":{}
}
]}
But never the number of inscription on the response. By the way i use function getNumberOfInscriptions() in other part of my code for make a validation and works.
Trying a lot of stuff i get to this:
I change the way I process the data from DB in the apply function and I treat it like an array.
exports.apply = async (courses) => {
var response = [];
for (let c of courses) {
var doc = c._doc;
var tmp = [{course: doc, inscriptionNumber: await courseUtils.getNumberOfInscriptions(c._doc._id)}];
response = response.concat(tmp);
}
return response;
}
I think is not a pretty good way to accomplish my goal, but it works. If I find something better, performance or clean I will posted.
Anyways I still don't know what I was doing wrong on my previous map function when I call my async-await function. If anybody knows, please let me know.

Wait until async is completed (await)

I am trying to get my head around with async/await
I am using https://github.com/sunnylqm/react-native-storage for my project in react-native.
I am using async storage to store few critical information such as selected user locale, I need to retrieve this value before screen is rendered to display screen based on selected locale.
I have tried implementing several helper functions, it works with callback, what I need is to return the value instead of callback and wait until the value is fetched. Below are few examples I tried.
// 1
_selectedLocale = async () => {
try {
const value = await global.storage.load({key: 'selectedLocale'});
return value
} catch (error) {
console.log(value)
}
}
var selectedLocale = _selectedLocale();
// 2
export async function _selectedLocale() {
return storage.load({key: 'selectedLocale'});
}
var selectedLocale = _selectedLocale();
// 3
export function selectedLocale(callback) {
storage.load({key: 'selectedLocale'}).catch(e => {
callback(RNLanguages.language);
}).then(function(locale) {
callback(locale);
});
}
This is not working, I am looking to
Implement a helper function to retrieve a value based on key
Wait until the value is retrieved (sync)
Can someone point me to right direction
Thanks
UPDATE1:
Here is how I am using the callback
selectedLocale(function(locale) {
global.layoutIsRTL = 'ar' == locale;
ReactNative.I18nManager.allowRTL(true);
global.i18n.locale = locale
});
UPDATE2:
It seems someone has already done this, here is the reference https://github.com/sunnylqm/react-native-storage/issues/206 unfortunately I am having hard time understanding it.
async implicitly returns a promise, so you need to await the function call as well if you want the value there:
var selectedLocale = await _selectedLocale();
but you can only do that inside of another async function

Categories

Resources