return Async/await sync node - node.js

In this err.length code always returns []. Where am I going wrong?
err.length does not wait for map result
router.post('/add', authSigs, async (req, res) => {
const nds = req.body.nds
const split = nds.split('\n')
const err = []
await split.map(async item => {
let sub = item.substr(0, 7)
const checkModel = await modelSerial.findOne({
'modelNds': sub
})
if (!checkModel) err.push(item)
})
if (err.length > 0) return res.status(400).send({error: 'Invalid'})
return res.status(200).send()
})

You're not awaiting on a Promise, you're doing await [Promise, Promise] so, your await isn't actually waiting for all the promises to resolve, you need to use Promise.all, which takes an array of promises.
The Promise.all(iterable) method returns a single Promise that
resolves when all of the promises in the iterable argument have
resolved or when the iterable argument contains no promises. It
rejects with the reason of the first promise that rejects.
const promises = split.map(async item => {
let sub = item.substr(0, 7)
const checkModel = await modelSerial.findOne({
'modelNds': sub
})
if (!checkModel) err.push(item)
});
await Promise.all(promises);
// Now all promises have been resolved
// err will contain items if there were any errors

Related

Async function returns Promise <Pending> instead of a value

Trying to log rs which should be the value of the function create order but it returns promise pending
let createOrder = async function () {
let response = await client.execute(request);
return response
};
let rs = createOrder().then((result) => console.log(result))
console.log("rsssss",rs)
You are not following the correct code pattern to handle async/Promises.
When you're chaining methods, the promise is resolved inside the callback, not outside.
The return of .then() method is a promise object.
The correct code is this:
let createOrder = async function () {
let response = await client.execute(request);
return response
};
createOrder().then((result)=> {
//the promise is resolved here
console.log(result)
}).catch(console.error.bind(console))

How to avoid no-async/await in loop?

We can easy refactor no await in loop if there is a single async/await. But sometime, in loop we have some awaits and the next await uses the result of previous await. So how to avoid that error with case multiple await in loop ?
I want to avoid this issue because I just added eslint rule to the project and no-await-in-loop is an error eslint reported. It's suggesting refactor to use Promise.all to run multiple async process in parallel. It can make increasing speed for performance.
ex:
for (const item in items) {
// first await
const firstResult = await getOneItem(...);
// second await
const secondResult = await getOneItem({ // conditions based on first result });
...
}
You'll need to pass a .then when inside the mapper function to Promise.all to wait for the first Promise to resolve and execute the second promise depending on its result. Something like:
return Promise.all(
items.map(
item => getOneItem(item)
.then((itemResult) => {
// insert desired logic here
return getOneItem(itemResult.someProperty);
})
)
);
If you have more than two, either keep returning .thens:
return Promise.all(
items.map(
item => getOneItem(item)
.then((itemResult) => {
// insert desired logic here
return getOneItem(itemResult.someProperty);
})
.then((secondItemResult) => {
// insert desired logic here
})
)
);
Or use an async function in the mapper callback so you can await:
return Promise.all(
items.map(
async (item) => {
const result1 = await getOneItem(item);
const result2 = await getOneItem(result1.someProperty);
// etc
)
);
You can use Array.prototype.map with an async callback:
await Promise.all(items.map(async item => {
let result1 = await getOneItem(item);
return getOneItem(result1);
}));

Promise.all with nested map.. First map only work others return empty objects in mongoose

Promise.all with nested map.. First map only work others return empty objects in mongoose nodejs iam using only one promise.all to warp both maps
This this code
let foundCategory = await Category.findOne({_id: req.params.id})
let CategoryWithSections = {...foundCategory.toObject(),sectionsOfCategory:
//this map work
await Promise.all( foundCategory.sectionsOfCategory.map(async(SOC)=>{
let sections= await Section.findOne({_id: SOC.sectionOfCategory })
return {...sections.toObject(), productsOfSections:
//this map doesn't work
sections.productsOfSection.map(async(POS)=>{
return await Product.findOne({_id: POS.productOfSection })
})
}
// return await sections.filter((section) => section._id === SOC.sectionOfCategory)
}) ) }
The productsOfSections object is filled with sections.productsOfSection.map which is array of promises. As your are not awaiting it, the promises are not instantly resolved.
The waiting for await is always bound to the most inner function it is in. Therefore the await Product.findOne({_id: POS.productOfSection }) is just bound to the async(POS)=>{ function, not to the async(SOC)=>{.
If you await all the promises in a similar way for the inner .map then it will create the "awaiting" chain which will returns you all the values
let foundCategory = await Category.findOne({
_id: req.params.id
})
let CategoryWithSections = {
...foundCategory.toObject(),
sectionsOfCategory:
//this map work
await Promise.all(foundCategory.sectionsOfCategory.map(async (SOC) => {
let sections = await Section.findOne({
_id: SOC.sectionOfCategory
})
return {
...sections.toObject(),
productsOfSections:
//this map doesn't work
await Promise.all(sections.productsOfSection.map(async (POS) => {
return await Product.findOne({
_id: POS.productOfSection
})
}))
}
// return await sections.filter((section) => section._id === SOC.sectionOfCategory)
}))
}
It is also good to mention that the async function just means that the function returns promise and then you are just working with the promises. It means that this part can be written without await and even without async function, because you are returning promise, therefore the result will be array of promises and thats something that Promise.all can work with
await Promise.all(sections.productsOfSection.map((POS) => {
return Product.findOne({
_id: POS.productOfSection
})
}))

How to push an object into an array in async function

i have been trying to insert an object into an array in async function ,but it
return an empty array as output in nodejs ,mongoose
var data = [];
app.get("/api/post", async (req, res) => {
const post = await UserPost.find();
post.forEach(async element => {
const email = await element.userid;
const user = await Account.find({ email });
const usern = await user[0].username;
var userobject = {
element,
usern
};
//Promise.all(userobject)
data.push(userobject);
});
console.log(data);
res.send({ data });
});
It seems you are struggling with promises. In order to achieve this specific scenario, you can use Promise.all and Array.map.
Here is a code I edited for you:
(*please note that this is just a dummy code for the sake of explanation)
app.get("/api/post", async (req, res) => {
try {
const posts = await dummyPromiseResolver(); // first promise
const promises = posts.map(async element => {
const user = await dummyEmailReturn(element.userid); // second promise
const usern = user[0].username;
return {
usern,
...element
};
});
const fresult = await Promise.all(promises);
res.send(fresult);
} catch (error) {
console.error("error in posts fetch:" + error);
}
});
If I describe this code, posts.map is creating an Array of promises since we need to iterate through every object in the array and needs to add values from separate promises.
Then Promise.all can execute your promise array and return final results array with your desired results.
Note: You can also use for … of as well but when we need to happen things parallelly we use Promise.all. You can find more information from this thread.
here is a link for code sandbox: https://codesandbox.io/embed/serverless-cookies-nu4h0
Please note that I have added dummyPromiseResolver and dummyEmailReturn which would be equal to UserPost.find() and Account.find() functions respectively. In addition to that, I removed a few unnecessary awaits in your code. I added a try catch block to catch any exceptions. You can change that try catch as you please.
hope this will help you. let me know if you need more clarifications.

Resolve all promises in Object

If you would have a function that would look smth like this:
async function foo() {
const myString = 'some string';
const myInt = 5;
const promise1 = fetchData(); // An async function returning a promise
const promise2 = fetchSomeOtherData(); // An async function returning a promise
return {
myString,
myInt,
promise1,
promise2,
}
}
And it would be important to me that fetchData() and fetchSomeOtherData() are executed at the same time (meaning adding await to both of these would not be a valid solution) is there a neat way to make the promises resolve when you call the function.
I am thinking of smth along the lines of Promise.all() just for an object that has SOME promises in it and not an array.
It is also important to me that my object keeps its structure as it is.
I am aware that there are some workarounds with Promise.all() where you cast the Object to an Array and reconstruct it afterwards but that wouldn't be as clean as I'd like it to be.
The way I would want to use the function and resolve the promises would be as follows:
const object = await foo();
and it should resolve both promises
async function foo() {
const myString = 'some string';
const myInt = 5;
const promise1 = fetchData();
const promise2 = fetchSomeOtherData();
return {
myString,
myInt,
promise1: await promise1,
promise2: await promise2,
}
}
A promise does not need await or .then() to start its execution. It starts to run once you create it and await/.then() are just two approaches to retrieve the execution result, but not to trigger the execution. Therefore when you run fetchData() and fetchSomeOtherData() they both start to execute immediately, and the second call does not wait for the first one.
This would resolve both promises before returning the object:
async function foo() {
const [result1, result2] = await Promise.all([
fetchData(),
fetchSomeOtherData(),
])
return {
result1,
result2,
}
}

Resources