Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use promise to avoid callback hell? [duplicate]

So I have a Posts collection

{
  id: String,
  comments: [String], # id of Comments
  links: [String], #id of Links
}

Comments: { id: String, comment: String, }

Links: { id: String, link: String, }

Find a post with comments and links belong to it by id:

Posts.findOne({id: id}, function(post) {
  Comments.find({id: post.id}, function(comments) {
    Links.find({id: post.id}, function(links) {
      res.json({post: post, comments: comment, links: links})
    })
  })
})

How to use Promise(http://mongoosejs.com/docs/promises.html) to avoid callback hell?

var query = Posts.findOne({id: id});
var promise = query.exec();

promise.then(function (post) {
  var query1 = Comments.find({id: post.id});
  var promise1 = query1.exec();
  promise1.then(function(comments) {
    var query2 = Links.find({id: post.id});
    var promise2 = query2.exec();
    promise2.then(function(links) {
      res.json({post: post, comments: comment, links: links})
    })
  })
});

Seems no good......

like image 385
Sato Avatar asked Mar 10 '16 00:03

Sato


People also ask

How do you avoid callback hell with promises?

We can avoid the callback hell with the help of Promises. Promises in javascript are a way to handle asynchronous operations in Node. js. It allows us to return a value from an asynchronous function like synchronous functions.

How do you use promise instead of callback?

To convert a callback into a promise, you need to return a promise. You run the code with the callback inside the promise. const readFilePromise = () => { return new Promise((resolve, reject) => { fs. readFile(filePath, options, (err, data) => { // ... }) }) }

How are promises more superior than callbacks How do promises solve the issue of callback hell?

They can handle multiple asynchronous operations easily and provide better error handling than callbacks and events. In other words also, we may say that, promises are the ideal choice for handling multiple callbacks at the same time, thus avoiding the undesired callback hell situation.

What is callback hell and how can it be avoided JavaScript?

This is a big issue caused by coding with complex nested callbacks. Here, each and every callback takes an argument that is a result of the previous callbacks. In this manner, The code structure looks like a pyramid, making it difficult to read and maintain.


2 Answers

You are nesting the callbacks. You don't need to do this. If you return a promise from .then then any .then you chain to it will be resolved when that promise gets resolved:

promise.then(post => Comments.find({id: post.id})
  .then(comments => Links.find({id: post.id})
  .then(links => {});

The comments query does not depend on links so you can actually do both queries at once:

promise.then(post => {
  return Promise.all([
     post,
     Comments.find({id: post.id}),
     Links.find({id: post.id}),
  ]);
}).then(data => res.json({
  post: data[0],
  comments: data[1],
  links: data[2],
});

If you use a library like bluebird you can also use something like the spread operator to make the names more transparent.


I would also look into using co for generator-based control flow as I think this is even clearer:

co(function* () {
  const post = yield Posts.findOne({id});
  const [comments, links] = yield [
    Comments.find({id: post.id}),
    Links.find({id: post.id}),
  ];

  res.json({post, comments, links});
});
like image 108
Explosion Pills Avatar answered Oct 13 '22 17:10

Explosion Pills


Try whit this:

function getPost(id) {
  return Post
    .findOne({id: id})
    .then( post => {
      return post;
    });
}

using Q module

function getCommentsAndLinks(post) {
  return Q.all([
    Comment.find({id: post.id}),
    Links.find({id: post.id})
  ])
  .done( results => {
    let comments = results[0];
    let links = results[1];
    return [post, comments, links];
  })
  .catch( err => {
  // handle err
  })

on controller

getPost(postId)
.then(getCommentsAndLinks)
.then( results => {
  let post = results[0];
  let comments = results[1];
  let links = results[2];
  // more code here
})
.catch( err => {
// handle err
}) 

but i suggest you not save string of IDS, save the instance of object, so you can use populate to get all data of comments and links, something like this:

Post
.findOne({id: id})
.populate('comments')
.populate('links')
.then( post => {
    // here have the post with data of comments and links
});
like image 4
DJeanCar Avatar answered Oct 13 '22 18:10

DJeanCar