Properties on awaited variable storing an object showing as undefined - javascript

I am trying to use some data that I get back from my mongodb atlas database and then use that data to perform another query. The calling function, selectGoalsForEpic(), calls and awaits findEpic(id). From the console.log statement I have in findEpic, I know that a valid object was found. My console.log statement after findEpic() call even shows [object Object] was returned and not undefined. I'm not sure why js doesn't allow you to view the contents of this variable here but that is beyond the scope of this question I guess. Anyway my next console statement says that epic.goals is undefined and my next query results in an error because of this. I thought await was supposed to pause execution and get the return value from a resolved promise but that doesn't appear to be the case here. Can someplease please explain to me what is going on here? Thanks
export const selectGoalsForEpic= async (id:string) => {
console.log("id is " + id);
const epic = await findEpic(id);
console.log("here epic" + epic);
console.log("EPIC " + epic.goals);
const goals = goalsCollection.find({_id:{$in: epic.goals}})
.toArray()
.then(res => {
return res;
})
.catch(err => {
console.log(`${FIND_EPIC_RESULT}: ${err}`);
});
return goals;
};
export const findEpic = (id:string):any => {
const epic = epicCollection.find({_id:{$oid: id}})
.toArray()
.then(res => {
console.log(res);
return res;
})
.catch(err => {
console.log(`${FIND_EPIC_RESULT}: ${err}`);
});
return epic;
};
// somewhere else calls
selectGoalsForEpic(my_id)

Use console.log("here epic", epic); so that doesn't display [object Object]. That will give you indications on why epic.goals is undefined

Related

Javascript JSON Fetch with await returns data but its function return an empty array

I'm trying to fiddle with fetching data from public APIs and then showing that data in a React component, the react part is not important tho, this is primarly a js issue. I'm using PokeApi for learning purpose, I create a new object with the data I need from the request, and then push that object to an array that the function returns when called:
// fetchPoke() function
let pokemons = []
// IDs is just an array with 20 random numbers between a range
IDs.forEach(async (id) => {
let url = `https://pokeapi.co/api/v2/pokemon/${id}`
await fetch(url)
.then((res) => {
if (!res.ok) {
console.log(`${id} not found`)
} else {
return res.json()
}
})
.then((data) => {
let pokemon = {}
pokemon.id = data.id
pokemon.name = data.name
pokemon.image = data.sprites.other.dream_world.front_default
pokemons.push(pokemon)
})
})
// function returns the array of object
return pokemons
But whenever I call this function
let pokemons = fetchPoke()
And then log it
console.log(pokemons)
Although I can see the content, it says it's an array of 0:
In fact if I try to console log pokemons.length I get 0
What could cause this? Am I doing something wrong in my fetch request?
So, you create an empty array.
You loop through you loop through the array, firing-off a bunch of asynchronous requests that will, as a side-effect, populate the empty array when the promises complete.
You immediately return the array without waiting for the promises to complete.
The requests probably have not even left your machine by the time this happens.
The array is empty at this point.
If instead, you declare your function as async and you map your IDs to a new array of promises, then await them all with Promise.all, then the promises will be able to complete before the function returns, and the resolved value of Promise.all will be an array containing your pokemons.
async function getSomePokemons(IDs) { // note, this is an async function
const promises = IDs.map((id) =>
fetch(`https://pokeapi.co/api/v2/pokemon/${id}`)
.then((res) => {
if (!res.ok) {
console.log(`${id} not found`)
// implicitly resolves as undefined
} else {
return res.json()
}
})
.then((data) => (data ? { // data might be undefined
id: data.id,
name: data.name,
image: data.sprites.other.dream_world.front_default
} : undefined))
)
const pokemons = await Promise.all(promises);
return pokemons;
}

console log of returned value shows a unusable response even after chaining a then to it

Im trying to return a promise is a javascript file. However, there is a weird issue. So when I console log the returned value within the function, it shows the following:
const id = getAccounts()
.then(res => res.find(acc => acc.type === ACCOUNT_TYPES.STARTER))
.then((res) => { return res.id });
console.log(id.then(res => res))
Is there anything I am missing? Have been dealing with this and research for the whole day. If anyone can help, I would highly appreciate it!
Updated section:
const initialState = {
currentAccountId: id.then((res) => { return res; }) || ''
};
The return value of calling a Promise's .then is always another Promise. By setting currentAccountId to id.then, it will always be a Promise.
You need to call this.setState from inside the Promise's resolve function:
componentDidMount() {
getAccounts()
.then(res => res.find(acc => acc.type === ACCOUNT_TYPES.STARTER))
.then((res) => { this.setState({ currentAccountId: res }); });
}
Use componentDidMount, like the React docs suggest, to initiate an async request. "If you need to load data from a remote endpoint, this is a good place to instantiate the network request."
Original answer
id.then will always return a new Promise, and that's what you are logging. To log the actual value you can move the console.log inside the resolve function:
id.then(res => console.log(res))

Not getting a result after async firebase "set( )" function

I do not get any result after I run the "set( )" function to the "res" variable when running this code, meaning that the "res" variable is undefined even though the docuement gets created in firebase. I have tried .then() .catch() too and that doesn't give me any kind of result either. The document gets created and everything works, and I if I want I can just return the Promise no matter the outcome of the firebase function, but that feels like it's bad practice since Im overlooking a possible error right?
Can I somehow get a result from "set( )" function? or in some other way make sure that the "set( )" function is successful?
exports.create = async function(listId, name, link) {
const newLinkRef = db.firestore.collection('links').doc();
const data = {
id: newLinkRef.id,
listId: listId,
name: name,
link: link
};
var res = await newLinkRef.set(data);
console.log(res)
if (res.id) {
return new Promise(resolve => {resolve({error: null, linkId: res.Id})})
} else {
return new Promise(resolve => {resolve({error: "Error creating lint"})})
}
}
(I use the "set( )" function over the "add( )" funciton since I want to save the random created Id inside the object stored to, and this was the simplest way I could find to do that)
set() returns a promise, but your use of await consume that promise and leaves res as the result that the promise wraps, which is void. So undefined seems correct there.
I think you're looking for:
try {
var res = await newLinkRef.set(data);
return {error: null, linkId: newLinkRef.Id};
}
catch (e) {
return {error: "Error creating lint"}
}
Alternatively you can not use await, and you end up with:
return newLinkRef.set(data).then(() => {
return {error: null, linkId: newLinkRef.Id};
}).catch (e) => {
return {error: "Error creating lint"}
})

Object Empty after adding values Axios

I am new to javascript and need help in fixing this. I read many articles but couldn't fix this, can someone correct my code.
Here,
links = an array of URLs containing javascript code,
response = the javascript code present at that URL
var code = {}
links.forEach(url => {
axios.get(url)
.then(response => {
code[`file${i++}.js`] = response.data
})
.catch(err => {
console.error(err)
})
});
// Come here only when the above loop has finished execution
// dosomething with variable code
console.log(code)
When I print variable code, it is an empty object. I want to collect all values in the code object and then proceed further.
Note- I want to proceed execution next when the above loop is finished.
Since you have an async call to populate the object, the data won't be available if you print immediately after the loop.
You should make use of async-await with Promise.all
async function someFunc() {
...
try {
var code = {}
const promises = links.map(url => {
return axios.get(url)
.then(response => {
code[`file${i++}.js`] = response.data
})
.catch(err => {
console.error(err)
})
});
await Promise.all(promises);
console.log(code)
}catch(err) {
console.log(err);
}
...
}

Vuex action not waiting to finish axios promise

I encounter a strange situation developing an application in Laravel + VueJS/Vuex stack.
I understand that if a promise is not returned the parent function calling it will not wait for it to resolve so things will go asynchronous. Axios returns a promise by default when calling a resourse through http.
So i have the parent function which looks like this:
fetchInvoiceSeries() {
var arr = []
let invsrs = this.$store.getters['getInvoiceSeries']
if (invsrs == null) {
return this.$store
.dispatch('get_invoice_series')
.then(() => {
invsrs = this.$store.getters['getInvoiceSeries']
if (invsrs != null) {
invsrs.forEach(function(s) {
arr.push({
value: s.id,
text: s.series + ' / ' + s.increment
})
})
this.series = arr
} else {
console.log('Error while fetching invoice series!')
}
})
.catch(e => {
console.log(e)
})
} else {
invsrs.forEach(function(s) {
arr.push({
value: s.id,
text: s.series + ' / ' + s.increment
})
})
this.series = arr
}
}
And here is the function defined in action part of the vuex module:
get_invoice_series({ commit }) {
return get('/api/series/0')
.then(response => {
if (response.data && typeof response.data !== undefined) {
let payload = response.data
commit('SET_INVOICE_SERIES', payload)
} else {
console.log('error', error)
}
})
.catch(error => {
console.log('error', error)
})
},
So as you can see i am returning the get request from axios inside the action. In the parent i am calling the action and the "then" keyword in order to do some processing after the action it's done. Also i am using arrow function because i need the context in the parent function in order to call this.$store ...
The problem is that even after checking the getter to see if the state have the invoice series and getting them using the get_invoice_series action i still don't have the invoice series in memory judging by the code i wrote. The console keeps loggin 'Error while fetching invoice series!' the first time i execute the code and the second time (after the information exists in state), the code skips fetching the invoice series (as expected).
Can you tell me what i am doing wrong ? Thank you!
Your error comes from invsrs being null the first time, and not null the second time.
This means that your function get_invoice_series({ commit }) is asynchronous, and that it returns a promise.
For more readability, maybe you should make your call independently from your return statement, using async/await expressions :
async get_invoice_series({ commit }) {
const response = await get('/api/series/0')
if (response.data === undefined) return null
const payload = response.data
commit('SET_INVOICE_SERIES', payload)
return payload
},
And then make your calls wait for this fetch to process :
async fetchInvoiceSeries() {
let arr = []
const invsrs = await this.$store.getters['getInvoiceSeries']
// ...
It's pure conjecture here, let me know if it helps or not.

Categories

Resources