This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 1 year ago.
I have an async function that checks the permission status in a device.
This is the function:
notificationsAllowed = async () => {
const allowed = await requestNotifications(['alert', 'sound']).then((res) => {
if (res.status == "granted") {
return true;
}
return false;
});
return allowed;
}
allowed is boolean, but when I try to use this function (for example, to set a switch to true or false) I get an object for some reason.
This is how I try to use it:
const allowed = NotificationsManager.getInstance().notificationsAllowed().then((res) => {
return res;
});
const [isEnabled, setIsEnabled] = useState(allowed);
It seems like allowed is of type Promise<boolean> but I can't use async await because it is inside a functional component.
You should use useEffect for something like this.
const [isEnabled, setIsEnabled] = useState(false);
useEffect(() => {
NotificationsManager.getInstance().notificationsAllowed().then((res) => {
setIsEnabled(res);
});
}, []);
This is not how async functions or await work. Normally, with Promises (like requestNotifications), you run it, it does its work in the background and then it runs the .then() function when it's done (at some point in the future).
await does what it says, and waits for the Promise to resolve/finish before continuing on. You don't need .then() here, since you are waiting for it to finish in a different way.
notificationsAllowed = async () => {
const allowed = await requestNotifications(['alert', 'sound']);
return allowed.status === "granted"
};
But now notificationsAllowed is an async function. So you either need to use .then() which runs it in the background or use await to wait for notificationsAllowed to complete.
const allowed = await NotificationsManager.getInstance().notificationsAllowed();
const [isEnabled, setIsEnabled] = useState(allowed);
Or you need to use a callback, which will run at some point in the future and not let you return a value:
NotificationsManager.getInstance().notificationsAllowed().then(allowed => {
const [isEnabled, setIsEnabled] = useState(allowed);
});
Related
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)
})()
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);
This question already has answers here:
How can I access the value of a promise?
(14 answers)
Closed last year.
const fetch = require('node-fetch');
async function loadPlacesWithImages() {
const responseObj = await fetch("https://byteboard.dev/api/data/places").then(response => response.json())
const placesArray = responseObj.places
for await (const place of placesArray) {
const imageObj = await fetch(`https://byteboard.dev/api/data/img/${place.id}`).then(response => response.json())
place.image = imageObj.img
}
console.log(placesArray)
return placesArray
}
// loadPlacesWithImages()
console.log(loadPlacesWithImages())
I don't understand why the console.log prints the populated array of objects but the function returns Promise { pending }.
I see that there are many questions with answers on this topic, but that still isn't helping me determine how to fix this.
Please help me learn! I would greatly appreciate it!
your function is async but you didn't await it in your last line.
It should be like this:
console.log(await loadPlacesWithImages());
When you call an async function you must use await to await for the function to complete:
// Promise.resolve just creates a promise that resolves to the value
const theAnswerToLife = () => Promise.resolve(42);
console.log(theAnswerToLife()); // Promise { pending }
(async () => { // create async context, not needed with top-level await
console.log(await theAnswerToLife()); // 42
})();
After an input change in my input element, I run an empty string check(if (debouncedSearchInput === "")) to determine whether I fetch one api or the other.
The main problem is the correct promise returned faster than the other one, resulting incorrect data on render.
//In my react useEffect hook
useEffect(() => {
//when input empty case
if (debouncedSearchInput === "") autoFetch();
//search
else searchvalueFetch();
}, [debouncedSearchInput]);
searchvalueFetch() returned slower than autoFetch() when I emptied the input. I get the delayed searchvalueFetch() data instead of the correct autoFetch() data.
What are the ways to tackle this? How do I queue returns from a promises?
I read Reactjs and redux - How to prevent excessive api calls from a live-search component? but
1) The promise parts are confusing for me
2) I think I don't have to use a class
3) I would like to learn more async/await
Edit: added searchvalueFetch, autoFetch, fetcharticles code
const autoFetch = () => {
const url = A_URL
fetchArticles(url);
};
const searchNYT = () => {
const url = A_DIFFERENT_URL_ACCORDING_TO_INPUT
fetchArticles(url);
};
const fetchArticles = async url => {
try{
const response = await fetch(url);
const data = await response.json();
//set my state
}catch(e){...}
}
This is an idea how it could looks like. You can use promises to reach this. First autoFetch will be called and then searchvalueFetch:
useEffect(() => {
const fetchData = async () => {
await autoFetch();
await searchvalueFetch();
};
fetchData();
}, []);
You can also use a function in any lifecycle depends on your project.
lifecycle(){
const fetchData = async () => {
try{
await autoFetch();
await searchvalueFetch();
} catch(e){
console.log(e)
}
};
fetchData();
}
}
Imagine the following hypothetical, minimal implementation of a function that does a simple HTTP GET request using axios. This uses await/async as depicted in the post.
const axios = require('axios')
exports.getStatus = async id => {
const resp = await axios.get(
`https://api.example.com/status/${id}`
)
return resp
}
Is the promise not resolved using await? Is it required that the client uses await as depicted below? Is it safe to assume that anytime a client consumes an async function, that it also needs to use await when calling the function?
// client
const { getStatus } = require('./status')
const response = await getStatus(4)
Short answer, no.
Labelling a function async means 2 things:
1) you're allowed to use await inside the function.
2) The function returns a promise; i.e. you can use await on its return value, or you can use .then, or Promise.all, or even ignore the return value, or anything else you can do with promises.
E.g. you could do the following which (depending on your use case) could be more performant because it needs not wait for the response to continue.
// client
const { getStatus } = require('./status')
const response4 = getStatus(4);
const response5 = getStatus(5);
// do stuff that don't rely on the responses.
response4.then(response => myOutput.setFirstOutput(response));
response5.then(response => myOutput.setSecondOutput(response));
Btw, your first snippet is redundant with its usage of await; it's equivalent to
const axios = require('axios')
exports.getStatus = id =>
axios.get(`https://api.example.com/status/${id}`);
This is because return await promise is equivalent to return promise, both return the same promise. There is one exception regarding rejected promises. Awaiting a rejected promise will throw an exception (which you can catch with a try/catch block), whereas directly returning a rejected promise will not throw an exception but you should still handle the rejection (with a .catch clause). To illustrate:
let promise = new Promise(resolve => setTimeout(() => resolve('resolved after 2 seconds'), 2000));
let returnPromise = () => promise;
let returnAwaitPromise = async () => await promise;
returnPromise().then(value => console.log('returnPromise,', value));
returnAwaitPromise().then(value => console.log('returnAwaitPromise,', value));
No, you don't need to use await. An async function returns a Promise that should be resolved. Instead of using await, you can simply call .then() like so:
// client
const { getStatus } = require('./status');
getStatus(4).then((response) => {
//Do something with the response
}).catch((error) => {
//Handle possible exceptions
});
Below I'll address your question from the comments. The getStatus function could be rewritten like this:
exports.getStatus = (id) => {
return new Promise((resolve, reject) => {
axios.get(`https://api.example.com/status/${id}`).then((resp) => {
resolve(resp);
}).catch((error) => {
reject(error);
})
});
}
It would act exactly the same as in your version. When you call asynchronous functions in series, you have to resolve each of the returned Promises. In your case, there are two of them - the one returned by axios.get and the one returned by getStatus.
No you don’t have to. The async function executes and waits until it returns error or completes execution and return a response!