Promise , Async Javascript Api [duplicate] - javascript

This question already has answers here:
async/await always returns promise
(4 answers)
Closed 12 months ago.
Ok, I think I am doing the promise wrong. I have 2 problems:
The results inside the class is working not problem. but when I retaive it at app.js it is showing as a promise.
The results inside the classrooms should be more than one row/object but it is only giving me one result
I am able to get the output I want inside the class, but in the following app.js I get this when I try to retraive the results values :
Promise {}
let results
document.getElementById('crypto').addEventListener('keyup', (e) => {
const cryptoInput = e.target.value;
console.log(cryptoInput);
if (cryptoInput.length > 2) {
results = crypto.getPrice(currency, cryptoInput)
//here I get Promise {<pending>}
console.log(results)
}
})
const table = document.getElementById('resultsTable');
let i = 0;
function showOptions(results) {
console.log(results)
}
the class is working :
class CoinGecko {
constructor() {
}
async list() {
const list1 = await fetch(`https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&order=market_cap_desc&per_page=250&page=1&sparkline=false`);
const list2 = await fetch(`https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&order=market_cap_desc&per_page=250&page=2&sparkline=false`);
const list1Json = await list1.json();
const list2Json = await list2.json();
const list = Object.assign(list1Json, list2Json);
//const list = list1Json.concat(list2Json);
return list;
//console.log(list);
}
async getPrice(currency = 'usd', crypto) {
let results=[];
const toutCrypto = await this.list().then(res => {
Object.keys(res).forEach(function (element){
if (res[element].id.startsWith(crypto) ||
res[element].name.startsWith(crypto) ||
res[element].symbol.startsWith(crypto))
{
//console.log();
results.push({
id: res[element].id,
name: res[element].name,
image: res[element].image,
symbol: res[element].symbol,
price: res[element].current_price,
date: res[element].last_updated,
})
console.log(results[0])
}
});
});
console.log(results[0].id)
return {
results
}
}
}

If 'results' in a promise then it won't execute until you trigger it by telling it how to resolve. To do this, you call Promise.prototype.then((resp) => {...})
Alternatively, you can declare your arrow functions and make them async and use await, but I would suggest that since you're new to Promises you do them the simple way and become accustomed to them. Once you understand how they work, you can use them with async/await, but since that is less intuitive you can stick to the basics.
crypto.getPrice(currency, cryptoInput)
.then(data => results = data)
.catch(err => console.error(err));
// simplified Promise chaining with catch method.

Related

Continuously showing a pending promise object despite calling the .then syntax and resolving it [duplicate]

This question already has answers here:
How can I access the value of a promise?
(14 answers)
Closed 3 months ago.
I am just trying to find out what in the world is going on here when trying to resolve the promise. Like my code below, I have been trying to take care and resolve the promise but it is just being a pain at this point even after searching for the answers all over.
const getTrades = async () => {
const accountId = accounts && accounts.find(account => account.type === 'EXCHANGE').id;
await getTradesInfo({ accountId: quadAccountId });
};
const pending = getTrades().then(res => { return res });
const resolved = pending.then(res => { return res });
console.log(resolved);
So for some reason, the resolved variable above is still showing a pending object.
your code is still asynchronous, your console log won't wait for your promise to be executed.
here a possible solution:
const getTrades = async () => {
const accountId = accounts && accounts.find(account => account.type === 'EXCHANGE').id;
return getTradesInfo({ accountId: quadAccountId });
};
getTrades.then((res)=> <here can use your console.log> )
or wrapping it with async/await:
const getTrades = async () => {
const accountId = accounts && accounts.find(account => account.type === 'EXCHANGE').id;
return getTradesInfo({ accountId: quadAccountId });
};
(async ()=> {
const result = await getTrades();
console.log(result)
})()

Why can I not return an array of objects in an async function?

In node.js I am trying to get a list of bid and ask prices from a trade exchange website (within an async function). Within the foreach statement I can console.info() the object data(on each iteration) but when I put all of this into an array and then return it to another function it passes as 'undefined'.
const symbolPrice = async() => {
let symbolObj = {}
let symbolList = []
await bookTickers((error, ticker) => {
ticker.forEach(symbol => {
if (symbol.symbol.toUpperCase().startsWith(starts.toUpperCase())) {
symbolObj = {
symbol: symbol.symbol,
bid: symbol.bidPrice,
ask: symbol.askPrice
}
console.info(symbolObj);
}
symbolList.push(symbolObj)
});
const results = Promise.all(symbolList)
return results;
});
}
const symbolPriceTest = async() => {
const res = await symbolPrice(null, 'ETH', true);
console.log(res)
}
I have tried pretty much everything I can find on the internet like different awaits/Promise.all()'s. I do admit I am not as familiar with async coding as I would like to be.
So, if the basic problem here is to call bookTickers(), retrieve the asynchronous result from that call, process it and then get that processed result as the resolved value from calling symbolPrice(), then you can do that like this:
const { promisify } = require('util');
const bookTickersP = promisify(bookTickers);
async function symbolPrice(/* declare arguments here */) {
let symbolList = [];
const ticker = await bookTickersP(/* fill in arguments here */);
for (let symbol of ticker) {
if (symbol.symbol.toUpperCase().startsWith(starts.toUpperCase())) {
symbolList.push({
symbol: symbol.symbol,
bid: symbol.bidPrice,
ask: symbol.askPrice
});
}
}
return symbolList;
}
async function symbolPriceTest() {
const res = await symbolPrice(null, 'ETH', true);
console.log(res)
}
Things to learn from your original attempt:
Only use await when you are awaiting a promise.
Only use Promise.all() when you are passing it an array of promises (or an array of a mixture of values and promises).
Don't mix plain callback asynchronous functions with promises. If you don't have a promise-returning version of your asynchronous function, then promisify it so you do (as shown in my code above with bookTickersP().
Do not guess with async and await and just throw it somewhere hoping it will do something useful. You MUST know that you're awaiting a promise that is connected to the result you're after.
Don't reuse variables in a loop.
Your original implementation of symbolPrice() had no return value at the top level of the function (the only return value was inside a callback so that just returns from the callback, not from the main function). That's why symbolPrice() didn't return anything. Now, because you were using an asynchronous callback, you couldn't actually directly return the results anyway so other things had to be redone.
Just a few thoughts on organization that might be reused in other contexts...
Promisify book tickers (with a library, or pure js using the following pattern). This is just the api made modern:
async function bookTickersP() {
return new Promise((resolve, reject) => {
bookTickers((error, ticker) => {
error ? reject(error) : resolve(ticker);
})
});
}
Use that to shape data in the way that the app needs. This is your app's async model getter:
// resolves to [{ symbol, bid, ask }, ...]
async function getSymbols() {
const result = await bookTickersP();
return result.map(({ symbol, bidPrice, askPrice }) => {
return { symbol: symbol.toUpperCase(), bid: bidPrice, ask: askPrice }
});
}
Write business logic that does things with the model, like ask about particular symbols:
async function symbolPriceTest(search) {
const prefix = search.toUpperCase();
const symbols = await getSymbols();
return symbols.filter(s => s.symbol.startsWith(prefix));
}
symbolPriceTest('ETH').then(console.log);

FindOne inside map returns no results

I'm trying to do a search using FindOne inside map but it never finds the data by Product Id. I don't understand the reason. Im using express on nodejs.
This is my code:
const calc = (details) => {
let grandSubtotal = 0;
details.map( async detail => {
const {verifyProduct} = await Product.find({ _id: detail._id});
console.log(detail._id);
console.log(verifyProduct); // UNDEFINED
...
Should be:
const result = await Promise.all(details.map( async (detail) => { … } ));
when you do it like you done you will get a pending promise object that never going to be resolved, I don’t know if you want to return some results, if no just do await Promise.all
Also this should be:
const calc = async (details) => { … }
Mongoose find returns a list of results. findOne returns an object.
The code is doing the equivalent of:
const {verifyProduct} = []
Use findOne to get an object to destructure, and test the result before use.
details.map( async (detail) => {
const res = await Product.findOne({ _id: detail._id });
if (!res) {
//throw new Error('No id '.detail._id)
console.log('No id', detail._id)
}
const { verifyProduct } = res
console.log(detail._id);
console.log(verifyProduct);
}
Also (as #antokhio noted), if you want to use the returned result array of the details.map you will need to await those as well.
You don't need await here
Product.find(({ _id }) => _id === detail._id );

Returning Data from a forEach inside a Promise [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 1 year ago.
I'm having issues returning a created Object the code is below:
Within the Promise.allSettled, I eventually get the results which I loop over and push each array to an object (This creates the object fine), when I try and return that said object, it's empty.
I think it's because my promise hasn't settled, I've tried doing:
Promise.resolve(returnedData) then returning it, and even .then(results => results).
What am I missing? I think I've looked at this for so long there's something clear as day I'm missing.
const getProductData = () => {
debugger;
const productIds = [];
const returnedData = [];
const customerLocation = getCustomerLocation();
productdataItems.forEach((product) => {
productIds.push(
product
.querySelector('[data-test-id="product-card-code"]')
.innerHTML.replace(/[^0-9]/g, ''),
);
});
const items = productIds.map((product) => ({
productCode: product,
quantity: 1,
}));
// Load in products for other steps
const promises = [];
productIds.forEach((sku) => {
promises.push(getProduct(sku));
});
Promise.allSettled(promises).then((results) => {
// Stock requires location data.
if (customerLocation) {
getEligibility(items, customerLocation).then((eligibility) => {
getStock([customerLocation.collectionBranchId], productIds).then(
(stock) => {
results.forEach((result, i) => {
if (result.value.product) {
returnedData.push({
Product: result.value.product,
Eligibility: eligibility[i],
Stock: stock[i].quantity,
ProductMarkup: productdataItems,
PostCode: customerLocation.deliveryPostcode,
});
}
});
},
);
});
}
});
return returnedData;
};
returnedData is outside the promise.allSettled. So it is getting returned before the Promise.allSettled completes and hence it is empty.
What you should be doing is moving the return of returnData inside Promises
return Promise.allSettled(promises).then((results) => {
... ...
return returnData;
}
The getProductData needs to be a async method that returns a promise result.

React - Returning data from API

I know there are similar questions, but I can't find the answer.
First, please tell me if I'm doing something really wrong
I need to populate my state with data from an API call. This was working fine with code above:
export const GetPlanets = async () => {
const planets = await axios.get(`${BASE_URL}`).catch((e) => {
console.error(e);
})
return planets.data.results
}
But then I needed to make a second call to several links from one json response filed, and I managed to make it work (don't know if it is the correct approach, though)
const GetPlanets = async () => {
let planetas = {}
await axios.get(`${PLANETS_URL}`)
.then((p) => {
planetas = p.data.results
return axios.get(`${FILMS_URL}`)
}).then((f) => {
planetas.films.forEach((v, i) => {
planetas[i].film = f
})
})
})
.catch((e) => {
console.error(e);
})
return planetas
}
This is my component file, where I try to get the object, like I was doing before
useEffect(() => {
const fetchPlanetas = async () => { // ME TRYING...
const planetas = await GetPlanets()
setPlanetas(planetas)
setToShow(planetas[0])
};
fetchPlanetas()
}, [])
But all I get is undefined
You're getting an array of undefined because .map() needs a return value. In both your .map() callbacks, you are not returning anything.
const results = [1, 2, 3, 4]
const results2 = results.map(elem => {
elem = elem + 1
})
console.log(results2)
But, even if you did return something in your .map() callback, GetFilms(f) is asynchronous, so you would not get the results of GetFilms() mapped into the array as you would expect.
You have a couple of options:
If you have access to the API, send the films data along with the rest of the data when you do your first request.
Use async/await and Promise.all() to get responses.

Categories

Resources