let shouldHavePaid = 0;
demographicsArray.map((country) => {
if (country.checked == true) {
Price.findOne({ country: country._id }).then((priceRes) => {
if (priceRes) {
shouldHavePaid = shouldHavePaid + priceRes.priceSMS * country.count;
} else {
shouldHavePaid = shouldHavePaid + 0.1 * country.count; //Default price for unlisted countries
}
});
}
});
console.log(`Finish: ${shouldHavePaid}`);
I want the console.log at the end to execute after the map, but it fires before the map is finished. I am expecting this output because as far as I know map should be sync and not async. I believe that the request to the DB messes it up? what would you suggest here?
let shouldHavePaid = 0;
demographicsArray.map((country) => {
if (country.checked == true) {
Price.findOne({ country: country._id }).then((priceRes) => {
if (priceRes) {
shouldHavePaid = shouldHavePaid + priceRes.priceSMS * country.count;
} else {
shouldHavePaid = shouldHavePaid + 0.1 * country.count; //Default price for unlisted countries
}
});
}
});
console.log(`Finish: ${shouldHavePaid}`);
I want the console.log at the end to execute after the map, but it fires before the map is finished. I am expecting this output because as far as I know map should be sync and not async. I believe that the request to the DB messes it up? what would you suggest here?
Share Improve this question asked Jun 29, 2020 at 15:17 PastaLoverPastaLover 4915 silver badges22 bronze badges 3-
3
1. Please don't use
.map
for a simple iteration. Use a loop or.forEach
for that. 2..map
is a synchronous operation, but you are launching asynchronous ones inside it. You either need to make all async and usePromise.all
and wait for all of the pletion (parallel) or convert to a regular loop andawait
every iteration (sequential). You can alsoreduce
to a single sequential operation but I'd probably go with the loop. – VLAZ Commented Jun 29, 2020 at 15:21 - Thanks, and why do you suggest not to use map for simple iterations? For the ability to use await? – PastaLover Commented Jun 29, 2020 at 15:46
-
1
It's the wrong tool and it's misleading. Mapping operations are 1:1 transformations. Using it for anything else is sending the wrong message to anybody who would be looking at the code in the future, including yourself.
.map
is an idiom in JavaScript and many other languages. There are many other better idioms for mon array operations. Check my profile information. – VLAZ Commented Jun 29, 2020 at 15:51
2 Answers
Reset to default 6You can use Promise.all
in bination with await:
await Promise.all(demographicsArray.map(async (...)=>{
if (...) {
await Prize...
if (priceRes) {
....
}
}
})
console.log(...)
Await can be used in async
functions to run the next line only after the promise pletes. Promise.all()
allows you to wait for a whole array of promises. Marking the callback as async
makes it return a promise, that can be used by the Promise.all()
. It also allows you to use await inside the function so you don't have to use .then()
.
Well, you are saying it your self pretty much
I am expecting this output because as far as I know map should be sync and not async. I believe that the request to the DB messes it up?
Your Price.findOne(expr)
returns a promise, so this part is async, so this is the root of your problem.
For your console.log to e at the end, and without making restructs to your code, just put it after the actuall record if fetched and the data pared!
let shouldHavePaid = 0;
demographicsArray.map((country) => {
if (country.checked == true) {
Price.findOne({ country: country._id }).then((priceRes) => {
if (priceRes) {
shouldHavePaid = shouldHavePaid + priceRes.priceSMS * country.count;
} else {
shouldHavePaid = shouldHavePaid + 0.1 * country.count; //Default price for unlisted countries
}
console.log(`Finish: ${shouldHavePaid}`);
});
}
});
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745496907a4630231.html
评论列表(0条)