HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptMinor

From Callbacks to Promises - MEAN Stack

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
stackmeanpromisescallbacksfrom

Problem

I have a MEAN Stack app in which I have been using mongoose routes to update my data. Some of those routes have a lot of back and forth in terms of updating data across multiple users and collections. So I used the standard mongoose callbacks to handle them. It all worked perfectly but it turned into Callback Hell! So I turned towards using promises.

My Question:

Although my new code is still quite long but I think its much easier to manage and maintain. What do you think about my move from callback to promises? Have I implemented it right? Is there anything else I can do to improve it?

Old CallBack Code:

(as you can see its callback hell and very confusing)

```
app.post('/bios/approve', isLoggedIn, function(req, res) {

if (req.user.accessLevel.indexOf('Bio Officer UK') > -1) {

Bio.findOneAndUpdate({userID: req.body.userID, bioForSector: req.body.bioForSector }, {
background: req.body.background,
experience: req.body.experience,
skills: req.body.skills,
otherSkills: req.body.otherSkills,
bioStatus: req.body.bioStatus,
approvalStage: "Bio Designer"

}, function(err, editedBio) {

if (err) {console.log("Error while editing Pending Bio is " + err);}

else if (editedBio) {
User.findOneAndUpdate({
accessLevel: "Bio Designer"
}, {
$push: {
biosPending: editedBio._id
}
}, function(err, user) {
if (err) {
console.log("The error while finding lineManager is " + err);
} else if (user) {
User.findOneAndUpdate({
accessLevel: "Bio Officer UK"
}, {
$pull: {
biosPending: editedBio._id
}
}, function(err, bioOfficer) {
if (err) {
console.log("The error while finding lineManager is " + err);
} else if (!bioOfficer) {

Solution

Assuming User and Bio functions all return promises, yes, looks about right for the most part.

_sendEmail looks like a one-off operation that doesn't appear to be part of the chain. Its errors won't get caught and will make it hard to debug. To make it part of the promise chain while still calling it parallel, use Promise.all together with _findBio. Promise.all accepts an array of promises, and resolves with an array of resolved values in the same order.

.then(function(designer){
  return Promise.all([_sendEmail(designer, req.body), _findBio(req.body)]);
})
.then(function(values){
  const email = value[0];
  const bio = value[1];
  return _findBioOfficer(bio._id)
})


_sendEmail also doesn't return a promise. You can easily wrap it in one.

return new Promise((resolve, reject) => {
  mailgun.messages().send(data, function(error, body) {
    if(error) reject(error);
    else resolve(body);
  });
});


text: 'Hi ' + designer.firstName + '\n This email is to inform you that ' + bio.firstName + ' ' + bio.lastName + ' has added their bio to the knowledge Base \n\n' +
  'Please login to the System & view and approve the bio so it can be finalised.\n\n' +
  'Thank you!\n'


If you're using Node 6+, you can use template literals.

Code Snippets

.then(function(designer){
  return Promise.all([_sendEmail(designer, req.body), _findBio(req.body)]);
})
.then(function(values){
  const email = value[0];
  const bio = value[1];
  return _findBioOfficer(bio._id)
})
return new Promise((resolve, reject) => {
  mailgun.messages().send(data, function(error, body) {
    if(error) reject(error);
    else resolve(body);
  });
});
text: 'Hi ' + designer.firstName + '\n This email is to inform you that ' + bio.firstName + ' ' + bio.lastName + ' has added their bio to the knowledge Base \n\n' +
  'Please login to the System & view and approve the bio so it can be finalised.\n\n' +
  'Thank you!\n'

Context

StackExchange Code Review Q#138348, answer score: 2

Revisions (0)

No revisions yet.