Why does async await not work in this function? - javascript

This might be a bit of a beginner question, but I can't figure this out:
I'm doing an asyncronous database call in which I want to get an object from the database and asign this object to the window object (window.naamID).
Next I want to run a function where I use the object assinged to the window object (making it global) and use it as a database query (.where("Vraagsteller", "==", naamID)).
The problem, of course, is that the second function starts running before the first function has fnished (because of it's asyncronous nature).
I wanted to overcome this problem by wrapping the second function in a syncronous function and await the first function.
This doesn't seem the work. The console says the object asigned to the window object is undefined.
This is the code:
function constructAuthMenu(){
auth.onAuthStateChanged(User =>{
const userRef = db.collection("Vitaminders")
.doc(User.uid);
userRef.get()
.then(function(doc) {
const naamID = doc.data().Gebruikersnaam;
const ID = doc.data().ID
const naam = naamID.replace(ID, "")
const profilePic = doc.data().Profielfoto
window.naamID = naamID
});
});
};
constructAuthMenu()
async function getNewReactions(){
await constructAuthMenu()
db.collectionGroup("Reactions")
.where("Vraagsteller", "==", naamID)
.where("New", "==",
"Yes").get().then(querySnapshot => {
querySnapshot.forEach(doc => {
*Do stuff*
});
});
What am I doing wrong? Or doesn't async await work like this?

If constructMenuFunction actually exists elsewhere in your code, and returns a Promise, then your problem is that you're missing parentheses on your function call: await constructMenuFunction();
If constructMenuFunction does not exist elsewhere in your code, and the first function preceding the async function is actually what you wish to invoke, your problem is that the first function does not return a Promise and your async function invokes the wrong method and without parentheses.
async function constructAuthMenu() {
return await auth.onAuthStateChanged(async User => {
try {
const userRef = db.collection("Vitaminders").doc(User.uid);
const doc = await userRef.get();
const naamID = doc.data().Gebruikersnaam;
const ID = doc.data().ID;
const naam = naamID.replace(ID, "");
const profilePic = doc.data().Profielfoto;
return naamID;
} catch(err) {
console.error(err);
}
});
};

Related

Why do one get two different outputs when querying data from firestore database with an async function?

I guess that I don't get the Google Firestore API for node.js the right way. So I want to ask what's happening in the background for the following two executions, because I get two different results.
First:
async function getDocument(db, path) {
const cityRef = db.doc(path);
const doc = await cityRef.get();
if (!doc.exists) {
console.log('No such document!');
} else {
console.log('Document data:', doc.data());
}
}
const aDatabase = admin.firestore();
const aPath = 'path/to/document';
getDocument(aDatabase, aPath);
This first code snippet I found in the Firestore documentation. It works as expected. The type of doc is DocumentQuerySnapshot. I can access the data of the document as usual. Everything fine. In the console the output is a JSON-Object containing my stored data.
Second:
async function getDocument(db, path) {
const cityRef = db.doc(path);
const doc = await cityRef.get();
if (!doc.exists) {
console.log('No such document!');
} else {
console.log('Document data:', doc.data());
return doc.data();
}
}
const aDatabase = admin.firestore();
const aPath = 'path/to/document';
const docData = getDocument(aDatabase, aPath);
console.log('docData:', docData);
This code snippet is only extended by the last two lines. In this case docData isn't a DocumentQuerySnapshot any more. It is a pending Promise. And that is the moment when I get irritated. I can't access the data of the document. I could, if I would do something like docData.then(...). But why is that what the function 'getDocument' returns suddenly a promise.
async functions always return promises. To get access to the eventual value, you either need to call .then on the promise and specify what code to run once the promise resolves:
getDocument(aDatabase, aPath)
.then(docData) => {
console.log('docData:', docData);
})
Or put your code in an async function and use await:
async function someFunction() {
// ...
const docData = await getDocument(aDatabase, aPath);
console.log('docData:', docData);
}
Note that even in your first example, you had to await a promise:
const doc = await cityRef.get();
This allows the rest of the async function to wait until the operation is complete before resuming. If you want the code that calls getDocument to wait too, then it needs to do an await as well.

My function call does not return the value

This is my code, i'm getting the values printed in console, but it's not returning that value.
async function fetchData(uid) {
return firebase.firestore().collection('users_info')
.where("uid","==",uid).get()
.then( async function(querySnapshot) {
var usr;
querySnapshot.forEach(async function(doc) {
usr = await doc.data().name;
console.log(usr);
return usr;
});
});
}
Since you are using a forEach I am assuming you are dealing with more than one data item. In that case, it might be better to push them all into an array and return that.
I am adding a slight modification of your snippet bellow. I think this should do the trick.
async function fetchData(uid) {
return firebase.firestore()
.collection('users_info')
.where("uid", "==", uid)
.get()
.then(async function(querySnapshot) {
var usr = [];
querySnapshot.forEach(async function(doc) {
const temp = await doc.data().name);
usr.push(await doc.data().name))
});
return usr;
})
}
Two things - first, you need to return a promise, if your function itself is doing async work that needs it's own callback to be continued from. See Return from a promise then().
Also, foreach is not necessarily used to return a collection of transformed values, which seems to be what you're trying to do there. I'd replace it with map if you can.

Await-ing a javascript event handler

I'm struggling with an event handler in javascript, I'm trying to make things respond correctly with async / await.
The issue in the code below is with the file.on event-- I'm struggling to promisify it correctly. Currently the checkSomething method returns before the file.on handler is finished, and so returnValue is always false.
I could use some advice and best practices.
What's a good way to go ensure returnValue is checked / set in the handler before the value is returned? I've tried putting the await keyword in front of the event handler, and in its callback function but that didn't work, and I'm basically scruffing along at this point and could use some tips. Thanks.
const axios = require('axios')
const fs = require('fs')
/*....*/
let isItChecked = await checkSomething()
async function checkSomething() {
let returnValue = false
const response = await axios.get('https://someUrl.com', {
responseType: 'stream'
})
const file = fs.createWriteStream('./localFile.txt')
response.data.pipe(file)
file.on('finish' () => {
performATask().then((result) => {
if (result == 'good') {
returnValue = true //need to make sure this is evaluated before returning
}
})
})
return returnValue
}
Since the event is only used as a signal for processing to continue, you can promisify and await its receipt before continuing with in-line style code. This also means that result need not be declared in outer scope of a nested fumction (which didn't work anyway due to being set asynchronously):
async function checkSomething() {
const response = await axios.get('https://someUrl.com', {
responseType: 'stream'
});
const file = fs.createWriteStream('./localFile.txt');
response.data.pipe(file);
await new Promise( resolve=> file.on(`finish`, resolve)); // wait here
const result = await performATask();
return result == 'good`;
}
You're close, you just have to return a promise, which resolves after the execution reaches your desired point (where you have the comment).
Other things to keep in mind:
Ensure you only use await from within async functions
Use === instead of ==
End statements with ;s
const axios = require('axios');
const fs = require('fs');
/*....*/
let isItChecked = await checkSomething();
async function checkSomething() {
const response = await axios.get('https://someUrl.com', {responseType: 'stream'});
const file = fs.createWriteStream('./localFile.txt');
response.data.pipe(file);
return new Promise(resolve =>
file.on('finish', () =>
performATask().then(result => resolve(result === 'good'))));
}

How do I store a value from a petition?

I want to get a value from an API and save that value for later, but I'm having troubles.
I get the result I want when I use console.log(), but when I do exactly the same thing with "return()" I get this result:
Promise{< resolved >:"The value I want"}
I'll show you my code:
const getDataAA = async () => {
const response = await fetch("https://s3.amazonaws.com/dolartoday/data.json")
const data = await response.json()
console.log("async/await based")
console.log(data.USD.transferencia)
}
When I call getDataAA() I get what I want in the console, but I want to store that value in order to use it, so I changed "console.log(data.USD.transferencia)" for "return(data.USD.transferencia)".
Then I do something like this in order to save the value:
let dolarPrice = getDataAA()
Why when I use "console.log" I get the value but when I use "return" I get also the promise?
const getDataAA = async () => {
const response = await fetch("https://s3.amazonaws.com/dolartoday/data.json")
return response.json()
}
let response = await getDataAA();
console.log(response);
-- EDITED
so this one another example how use it.
the async method (getDataAA) have to return something.
everytime you need to call an async method you have to use await (
if you wait until it's completed)
everytime you use await the method must be async.
<!DOCTYPE html>
<html>
<script type="text/javascript">
var f = async () => {
const getDataAA = async () => {
const response = await fetch("https://s3.amazonaws.com/dolartoday/data.json")
return response.json()
}
let response = await getDataAA();
console.log(response);
}
f();
</script>
</html>
I discovered I way to solve this! I defined a variable outside the function and then the function stored the value I wanted inside that variable. This is my code:
const getDataAA = async () => {
const response = await fetch("https://s3.amazonaws.com/dolartoday/data.json")
const data = await response.json()
console.log("async/await based")
dolarPrice = (data.USD.transferencia)
}
let dolarPrice
getDataAA()
That way I stored the value inside the "dolarPrice" variable. Thanks all the people who answered my question, I found the solution thanks to all of you.

Fetching return value from async function

I am trying to capture the response of two service calls within a function. Got to know that async and await will solve this purpose and tried below. Here inside async function ex - I am making a call to users, companies end point and console log is displaying perfect, but while retrieving the same value by calling the async function is giving Promise Pending. I tried two options 1. by simply calling the async function - giving Promise Pending 2. by calling with await prefixed - giving await is a reserved word.
Please let me know how to capture the response from this...
const service = {
getUsers: () => axios.get(`http://localhost:3000/users`),
getCompanies: () => axios.get('http://localhost:3000/companies')
};
let ex = async () => {
let users = {};
let companies = {};
try {
users = await service.getUsers()
companies = await service.getCompanies()
console.log('Example ', {
users: users.data,
companies: companies.data
})
} catch (err) {
console.log(err);
}
return [{ users, companies}];
};
//let resp = await ex(); - giving await is a reserved word
// let resp = ex(); - giving Promise is pending..
console.log(resp);
All async functions will always return a promise. If you return nothing, the function will return a promise for undefined. Whatever you return will get wrapped up in a promise, which you need to await or call then on to access the value inside.
resp.then(console.log)

Categories