async call is not working inside this block in JS [duplicate] - javascript

This question already has answers here:
Using async/await with a forEach loop
(33 answers)
Closed 1 year ago.
I am trying to use forEach in array of object and based on the following condition send a request and get that response for using in the other call. Here is the code:
products.forEach(product => {
if (
product.type === 'shows' &&
product.isSoldOut &&
product.otherData
) {
delete product.brand.brandId
product.brand.isTop = true
const res = apiService.create(product.brand)
console.log(res)
}
})
When I add await const res = await apiService.create(product.brand) here it shows a warning too. How can I use async await in this scenario or is there other way to overcome this issue?

From await documentation:
"The await operator is used to wait for a Promise. It can only be used inside an async function".
You need to turn your callback in forEach to async:
products.forEach(async (product) => { ... })

You need to mark the callback as async to allow you to use await.
They always have to come in pairs.
e.g.
products.forEach(async (product) => {
if (
product.type === 'shows' &&
product.isSoldOut &&
product.otherData
) {
delete product.brand.brandId
product.brand.isTop = true
const res = apiService.create(product.brand)
console.log(res)
}
})

Other answers correctly point out that you may just need to mark the method as async. But in this situation where you are firing multiple async calls often you want them to all be fired at the same time, then wait for them to all be resolved. This can be accomplished with Promise.all()
await Promise.all(products.map((product) => {
if (
product.type === 'shows' &&
product.isSoldOut &&
product.otherData
) {
delete product.brand.brandId
product.brand.isTop = true
return apiService.create(product.brand)
}
}));

Related

how to wait for foreach in firebase data retrive process [duplicate]

This question already has answers here:
Using async/await with a forEach loop
(33 answers)
Closed 2 years ago.
async onclick(){
let number=this.state.phoneNumber
if(number !== null && number.length===10){
console.log('number',number)
await firestore().collection('profile')
.where('mobile', '==', number).get().then(snapshot => {
if (snapshot.empty) {
}
else{
console.log(snapshot.data())
const res=Promise.resolve(async function(){
let data=[]
await snapshot.forEach(doc => {
data.push({data:doc.data().uid})
})
return data
})
if(res.length !==0){
res.then((pra)=>{
let payload={Requester:auth().currentUser.uid,Responder:pra}
firestore().collection('requests').add(payload).then(function() {
goHome();
});
})
}
}
})
}
else{
showSnackbar('Please enter valid mobile number');
}
}
this is the my code here here i want to wait for foreach to complete the after this is want to save the data received from the this foreach to firebase but issue is that before the foreach finish it is running the quert so i am getting null data in firebase
The issue is not async/await, your res is a Promise, and the length will always be undefined. For example:
var p = Promise.resolve([1,2,3]);
console.log(p.length) // undefined
Could you try with this correction?
const res = await Promise.all( snapshot.map( doc => doc.data().uid ) );

new promise inside a async function in order to grab the value outside of the async function

I am returning a new Promis inside a async function that is doing a request to a api, I can console log the request from the api just fine inside the function. But when I try and resolve the same line I consoled document.sold it does not work. I expected the checkPriceId variable to return a promise which I could then catch with .then, but that does not seem to work. I have also tried using promise.all around the documents.forEach loop to no avail.
Any help would be greatly appreciated.
Here's the code
const checkPriceId = async test => {
return new Promise((resolve, reject) => {
const query = `*[_type == "products" && price_id == "${body.price_id}"]`
client.fetch(query, {}).then(documents => {
documents.forEach(document => {
//console.log(document.sold)
resolve(document.sold)
})
})
})
}
checkPriceId.then(test => {
console.log(test) // does nothing
})
console.log(checkPriceId) // just returns a async function
checkPriceId()
Why use the Promise constructor at all? client.fetch already returns a promise, and you're also inside an async function which also returns a promise. Assuming all documents have a .sold that you're trying to get back in an array:
const checkPriceId = async () => {
const query = `*[_type == "products" && price_id == "${body.price_id}"]`
const documents = await client.fetch(query, {})
return documents.map(({ sold }) => sold)
}
checkPriceId.then((soldList) => {
console.log(soldList)
})
This also removes the test argument to checkPriceId since it wasn't being used.
As #blex mentinoned, you are not calling checkPriceId on line 13.
However, as also mentioned by #grodzi, you cannot resolve your promise multiple times. Once the resolve fn is called once (on line 7), subsequent calls will be ignored.
Since mixing Promises and async the way you are can be verbose and opaqueI'd suggest you just use async/awiat here. This will greatly help your code readability.
Here's a fixed example:
const checkPriceId = async (test) => {
const query = `*[_type == "products" && price_id == "${body.price_id}"]`;
const documents = await client.fetch(query, {}); // this could throw
return documents.map(document => document.sold);
}
checkPriceId().then(test => {
console.log(test) // this will log the return value from line 7
})

async/await in forEach loop [duplicate]

This question already has answers here:
Using async/await with a forEach loop
(33 answers)
Closed 2 years ago.
The below JavaScript is returning a strange version of an array. The below forEach logs nothing to console. I'm probably missing something quite fundamental here, but I know for a fact that the array is populated...unless it's not populated until later due to being async and Chrome just evaluates the console.log after the fact?
let damageRollStringArr = []
monster.damage_types.forEach(async (damageTypeName) => {
const damageType = await checkResponseAndReturnValue(await DamageTypesService.findDamageType(damageTypeName.trim()))
if (damageType !== null) {
damageRollStringArr.push(damageType.damage)
}
})
damageRollStringArr.forEach(el => console.log(el))
// Was returning an empty array[] with objects inside?
return damageRollStringArr
Thanks
demageRollStringArr.forEach (2nd foreach) wont wait for monster.demage_types.forEach (1st foreach) to execute although there is async await in the first forEach
To achieve what you want to do, try this,
let damageRollStringArr = []
const promises = monster.damage_types.map(async (damageTypeName) => {
const damageType = await checkResponseAndReturnValue(await DamageTypesService.findDamageType(damageTypeName.trim()))
if (damageType !== null) {
damageRollStringArr.push(damageType.damage)
}
})
await Promise.all(promises)
damageRollStringArr.forEach(el => console.log(el))
return damageRollStringArr
Or, you can use normal for() loop to replace 1st foreach
let damageRollStringArr = []
for(let i = 0; i < monster.demage_types.length; i++) {
const damageType = await checkResponseAndReturnValue(await DamageTypesService.findDamageType(damageTypeName.trim()))
if (damageType !== null) {
damageRollStringArr.push(damageType.damage)
}
}
damageRollStringArr.forEach(el => console.log(el))
return damageRollStringArr
1st solution will run the loop parallel,
2nd solution will run the loop sequential

Async/Promise issues when adding a Gatsby node field

I'm having some issues adding some fields on to a Gatsby node. The real issue comes down to the fact that I just can't seem to wrap my head around the asynchronous situation, since I'm creating these fields from API call results. I'm still trying to learn about promises/async/etc.
I make one API call to an API to get location information and add it as a field (locationRequest, which is working just fine), and then run another call to get the orthodontists that work at that location.
When getOrthos runs, and it gets up to the console.log that should be spitting out an array of orthodontist entities, I'm getting this instead:
Created Ortho Node... [ Promise { <pending> }, Promise { <pending> } ]
What am I doing wrong? I've tried to go through some Promise tutorials, but I can't figure out the best way to do this where it returns the actual data rather than the promise.
Thank you for any guidance you can provide, and please excuse my ignorance.
const yextOrthos = node.acf.location_orthodontists;
const locationRequest = async () => {
const data = await fetch("https://FAKEURL.COM")
.then(response => response.json());
if( data && data.response && data.response.count === 1 ){
createNodeField({
node,
name: `yextLocation`,
value: data.response.entities[0]
});
} else {
console.log("NO LOCATIONS FOUND");
}
};
const getOrthos = async () => {
let orthodontists = await yextOrthos.map( async (ortho, i) => {
let orthoID = ortho.acf.yext_entity_ortho_id;
return await orthoRequest(orthoID);
});
if( orthodontists.length ){
createNodeField({
node,
name: `yextOrthos`,
value: orthodontists
});
console.log("Created Ortho Node...", orthodontists);
} else {
console.log("NO DOCTORS FOUND");
}
};
const orthoRequest = async (orthoID) => {
const dataPros = await fetch("https://FAKEURL.COM").then(response => response.json());
if( dataPros && dataPros.response && dataPros.response.count === 1 ){
return dataPros.response.entities[0];
} else {
return;
}
}
locationRequest();
getOrthos();
What you need to remember is that await should only stand before promise or something that returns promise. Array.prototype.map() returns array so you can't use await with it directly. Promise.all() on the other hand accepts an array and returns a promise. The example Jose Vasquez gave seems sufficient.
Good luck
You should use Promise.all() for arrays, on this line:
let orthodontists = await Promise.all(yextOrthos.map( async (ortho, i) => {...});
I hope it helps!
Edit:
A Promise which will be resolved with the value returned by the async
function, or rejected with an uncaught exception thrown from within
the async function.
If you wish to fully perform two or more jobs in parallel, you must
use await Promise.all([job1(), job2()]) as shown in the parallel
example.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function

Async Await does not work as expected [duplicate]

This question already has answers here:
Using async/await with a forEach loop
(33 answers)
Closed 5 years ago.
Currently we are storing short strings as keys.
These keys correspond to long values which are labels.
I am trying to update the corresponding long value for the key.
But the console.log(record) always executes first and then the inner log statement executes which is not is desired. It always sends the unmodified record to the getRadioValues function caller.
I want to return the record after the corresponding key is updated.
export const getRadioValues = (record: IRecordInput) => {
const singleSelectKeys = ['Race', 'DeathWas', 'MannerOfDeath'];
singleSelectKeys.forEach(async key => {
if (record[key]) {
const dropDownOption = await DropDownOptions.find({ where: { id: record[key] }}) as IPDFSelect;
record[key] = dropDownOption.dataValues.Text;
console.log(record[key]);
}
});
console.log(record);
return record;
};
Your forEach is using an async function which means that the loop probably finishes before any of the promises it created do. To fix this, you need to get the result of your promises and wait on them. However, this means the enclosing function must itself be async, which may or may not be acceptable for your actual use case.
export const getRadioValues = async (record: IRecordInput) => {
const singleSelectKeys = ['Race', 'DeathWas', 'MannerOfDeath'];
await Promise.all(singleSelectKeys.map(async key => {
if (record[key]) {
const dropDownOption = await DropDownOptions.find({ where: { id: record[key] }}) as IPDFSelect;
record[key] = dropDownOption.dataValues.Text;
console.log(record[key]);
}
}));
console.log(record);
return record;
};

Categories