Hello there overflowers,
I'm currently working on a project of mine, using a node server with a mongo data store. I'm currently writing some functions to populate the database for me.
Examples of objects in the database are Users,Classes,School Years,Students ratings, etc.
All the functions to create such objects are implemented like this :
function popUser(users){
chain = [];
users.forEach((v,i,a)=>{
let p = new Promise(function(res,rej){
let newU = new User(v);
newU.save(()=>{
err && rej(err);
res();
});
});
chain.push(p);
});
return chain
}
In the remainder of my population module i invoke such functions depending on my needs. The order in which the above functions are called is important, thus I don't want fully parallel execution of constructors.
With Promises I could do something like this :
popUser(users).then(popClasses).then(...). ... .catch((err)=>{})
With Promises Chains I know that I can do the following
Promise.all(usersChain).then(()=>{
//make a new chain for Classes
Promise.all(classesChain).then (()=>{},(err)=>{})
},(err)=>{})
I think we can agree that it becomes quite hard to read and understand, thus the question :
Is there a way of achieving the same results with a different, more readable syntax?
Edit : to be clearer, usersChain and cleassesChains are arrays of Promises to create and insert some object (or objects) into the database. I can not make a single chain because some objects might have to be inserted after some other objects have already been inserted.
Edit : Wait, can I just call
Promsie.all(populateCountersPromise).then(promise1).then(promise2).catch((err)=>{})
There are different parts in the code that won't work, or should not be written that way.
If you use shortcuts like this:
err && rej(err);
res();
You should know what they mean, because this is equal to:
if( err ) {
rej(err);
}
res();
So if an error occurs both rej
and res
are called.
From your popUser
you return an array of Promises, so popUser(users).then(popClasses)
would fail, because you cannot call .then
on an array.
The first thing you should do, is to clean up your popUser
function:
function popUser(users) {
let promises = users.map((v, i, a) => {
return new Promise(function(res, rej) {
let newU = new User(v);
newU.save(err => {
if (err) {
rej(err)
} else {
res()
}
});
});
});
return Promies.all(promises)
}
Use .map
instead a forEach
with a push
, because it makes it clear right from the beginning what you do. And use Promies.all
to return a Promise from your function that waits for all users to be saved, if you do the same for popClasses
you can write it like:
popUser(users)
.then(popClasses)
.then(...)
.catch((err)=>{})
If you really want to write it like in your last code snippet, then change it to this:
Promise.all(usersChain)
.then(() => Promise.all(classesChain))
.then(() => {})
.catch(err => {})
Many APIs now adays support both the classical callbacks and Promises, so you could improve your popUser
further:
function popUser(users) {
let promises = users.map(v => new User(v).save())
return Promies.all(promises)
}
Mongoose callbacks are legacy API. Mongoose supports promises for a long time and doesn't need to be promisified.
For concurrent promises, forEach
can be replaced with map
, this is exact use case for the latter:
function popUser(users){
return Promise.all(
users.map(userData => new User(userData).save())
);
}
async..await
can be used in the rest of the cases where promises should be sequential:
try {
await popUser(users);
await popClasses();
...
} catch (err) {
...
}
Why not return Promise.all(chain)
in function popUser
.
Returning a Promise is better to match semantic of popUser
which is a function of doing something asynchronously.Returning array of promise is confusing.
Then you can use popUsers.then(popClasses).then(...). ... .catch((err)=>{})
popUsers.then(popClasses).then(...). ... .catch((err)=>{})
to queue up promises
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.