Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

I have code that looks something similar to:

const MyClass {
  checkExists: function(db_client) {
    return new Promise(fulfill, reject) {
      var sql = 'select * from table';
      db_client.connect().then(c => {
      }).then(res => {
        client.release();
        fulfill(res.rows[0].col1 === 1 ? true : false);
      }).catch(error => {
        reject(error);
      });
    });
  }
  doSomething: function(db_client) {
    return new Promise(fulfill, reject) {
      var sql = 'delete from table where x=1';
      db_client.connect().then(c => {     
      }).then(res => {
        fulfill();
      }).catch(error => {
        reject(error);
      });
    });
  }
};

module.exports = MyClass;

var myc = require('./MyClass.js');

myc.checkExists(db_client).then(resp => {
  if(resp === true) {
    myc.doSomething(db_client).then(resp => {
    console.log('success.');
  } else {
    console.log('we are done.');
  }
  }).catch(error => {
    console.log(error);
  });
}).catch(error => {
  console.log(error);
});
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
133 views
Welcome To Ask or Share your Answers For Others

1 Answer

Is there a better way to handle nested promises in NodeJS?

Yes, there is. Lots of improvements you can make. Your pseudo-code seems to be missing some pieces to it, but I'll show the simplest version I can that captures the spirit of what it looks like you were doing:

const MyClass {
    checkExists: function(db_client) {
        var sql = 'select * from table';
        return db_client.connect().then(c => {
            // missing code here in your pseudo code
            // do something with c here to create the variable res
            client.release();
            // make this be the resolved value of the returned promise
            return res.rows[0].col1 === 1;
        });
    }
    doSomething: function(db_client) {
        var sql = 'delete from table where x=1';
        return db_client.connect().then(c => {
            // do something with c here
            // return value or another promise
        });
    }
  };

  module.exports = MyClass;

  var myc = require('./MyClass.js');

  myc.checkExists(db_client).then(resp => {
    if(resp === true) {
        return myc.doSomething(db_client).then(resp => {
            console.log('success.');
            // return something here to be the resolved value of the promise
            return resp;
        });
    } else {
        console.log('we are done.');
        // return something here to be the resolved value of the promise
        return resp;
    }
  }).catch(error => {
    console.log(error);
  });

Here are the basic concepts:

  1. Don't wrap an existing promise with a manually created promise. That's referred to as an anti-pattern and it provides no benefit, balloons your code and is an opportunity for error handling mistakes. Just return the promise you already have.

  2. Chain embedded promises from within a .then() handler by returning the promise from the .then() handler.

  3. You don't need to .catch() at every level unless you explicitly need to do something at the lower level. Rejected promises will automatically propagate up the chain to the next .catch(). This can vastly simplify error handling.

  4. If you need a .catch() at a lower level, even just for logging purposes, then you must throw an error from the .catch() to keep the promise rejected, otherwise the rejection will be considered "handled" and the chain will switch to resolved.

  5. In a .then() handler, you have three options. You can return another promise and it will be added into the chain. You can return a value and it will become the fulfilled value of the parent promise chain. You can throw an exception and the current chain will become rejected. If you return nothing, then the fulfilled value of the parent promise chain becomes undefined (just like a function that returns nothing).

FYI, here are a couple articles on promise anti-patterns which are worth studying and putting into practice:

Six Promise Anti-Patterns

Deferred and .then(success, fail) anti-patterns

Other notes about your code:

  1. In some places it looks like you're missing code to release a database connection.

  2. When designing, you should be very clear about a function that just handles an operation on its own (including errors) and there is no expectation that a caller will handler the error vs. a function whose job it is to carry out an operation and return the result or error so that caller can decide what to do with them. This determines whether you just let the rejected promises get returned (for the caller to deal with) or whether you have to .catch() them here and do something with them.

  3. If you .catch() to clean up or log or something like that, but want the caller to still see the error, you have to re-throw the error so the promise stays rejected after your .catch() runs.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...