7

I am trying to understand promises in node.js. Here is a sample code

con.queryReturnPromise("SELECT * FROM bookings WHERE driverId = " + accId + " AND bookingStatus = " + config.get('BOOKING_STATUS_ACTIVE') + " LIMIT 1")
  .catch((err) => {

    callback({
      "message": "Success",
      "error": true,
    });
    console.log("mysql query error");
    return Promise.reject();
  })
  .spread((rows, fields) => {
    if (rows.length != 1) {
      return Promise.reject();
    }
    mBooking = rows[0];
    var query = "INSERT INTO locations SET timeStamp = " + timeStamp + " latitude = " + lat + ", longitude = " + lng + ", bookingId = " + mBooking.id;
    return con.queryReturnPromise(query)
  })
  .catch((err) => {
    if (err)
      console.log("Adding Location error" + err);
    return Promise.reject();
  })
  .spread(() => {
    return funcs.getBooking(con, mBooking.id)
  })
  .then((booking) => {
    if (mBooking.userId.toString() in userSockets) {
      userSockets[mBooking.userId].emit(config.get('EVENT_USER_UPDATE_BOOKING'), {
        "message": "Success",
        "error": false,
        "booking": booking
      });
      userId = mBooking.userId.toString();
    }
    callback({
      "message": "Success",
      "error": false,
      "booking": booking
    });
  })
  .catch((err) => {
    if (err)
      console.log(err);
  });

The code is quite simple. However i have one confusion. If return Promise.reject() is being called, where would the function lead to, Which code will be called. E.g if the first catch clause is called and it calls return Promise.reject() where part of below code will run afterwards

Promises in for loop

data = JSON.parse(data);
            var promisesArray = [];
            for (var i = 0; i < data.length; i++) 
            {
                var location = data[i];
                var lng       = location.lng;
                var lat       = location.lat;
                var bearing   = location.bearing;
                var deltaTime = location.deltaTime;
                var timeStamp = location.timeStamp;

                var query = "INSERT INTO locations SET timeStamp = " + timeStamp + " latitude = " + lat + ", longitude = " + lng + ", bookingId = " + mBooking.id;


                var promise = con.queryReturnPromise(query)                    
                        .then( () => {                            
                        });

                promisesArray[] = promise;
            }

            Promise.all(promisesArray)
            .then(function(results)
            {
                    callback({
                        "error": false,
                    });            
            });
Muhammad Umar
  • 11,391
  • 21
  • 91
  • 193
  • 1
    Correct me if I'm wrong, but there should be only one `catch()` method call in the chain. If you want to support catching errors after each step, then you should provide the error callback as a second param in `then()` method. – sunpietro Sep 28 '16 at 06:29
  • Just a note: The use of `.spread()` is discouraged when you have ES2015 syntax, use `.then(([rows, fields]) => { ... })` instead. – Madara's Ghost Sep 28 '16 at 07:22
  • @MadaraUchiha Why it is discouraged? Performance? – thefourtheye Sep 28 '16 at 07:24
  • 1
    @thefourtheye Possibly, but I think it has more to do with portability. `.spread()` is only available in Bluebird, whereas `.then(([]) =>` is available in all Promise implementations. – Madara's Ghost Sep 28 '16 at 07:31

1 Answers1

14

Each time you do return Promise.reject(), the next .catch() handler in that chain will get called. It will skip any .then() handlers up until the next .catch() handler.

Returning a reject promise from either a .then() handler or a .catch() handler makes the current promise chain be rejected. So, as more handlers down the chain are encountered, the next reject handler in the chain will get called.

When you hit a .catch() handler, what happens after that .catch() depends upon what the .catch() does. If it throws or returns a rejected promise, then the promise stays in the rejected state and the next .catch() in the chain will execute. If it returns nothing or any regular value (other than a promise that ultimately rejects), then the promise becomes resolved (no longer rejected) and then next .then() handler in the chain runs.

Here's an example:

a().then(function() {
    // makes promise chain assume rejected state
    return Promise.reject();
}).then(function() {
    // this will not get called because promise is in rejected state
}).catch(function() {
    // this will get called
    // returning a reject promise will keep the promise in the reject state
    return Promise.reject();
}).then(function() {
    // this will not get called because promise is in rejected state
}).catch(function() {
    // this will get called
    return 2;
}).then(function(val) {
    // this will get called because prior `.catch()` "handled" the rejection
    // already
    console.log(val);    // logs 2
}).catch(function() {
     // this is not called because promise is in resolved state
});
jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • so if i get reject in first catch clause then systematically all catch clauses in my code will run? – Muhammad Umar Sep 28 '16 at 06:35
  • 2
    @MuhammadUmar - No. Only the next `.catch()` in that chain runs. What happens after that `.catch()` depends upon what that `.catch()` returns or throws. If it returns a rejected promise or throws an exception, then the next `.catch()` will run. If it returns nothing or a normal value, then the promise becomes resolved and the next `.then()` handler will run. – jfriend00 Sep 28 '16 at 06:36
  • if u see my code the next catch has error and then again returning rejection. So the console will log an error and will switch to next catch – Muhammad Umar Sep 28 '16 at 06:37
  • @MuhammadUmar - See what I added to my previous comment. – jfriend00 Sep 28 '16 at 06:38
  • Thanks that was quite helpful, one question, if i have to update a query in a for loop, can u explain its syntax e.g if i have to update 10 rows – Muhammad Umar Sep 28 '16 at 07:12
  • @MuhammadUmar - I've answered your original question. If you have a NEW question about a new subject (apparently involving a `for` loop), then you should ask a new question, not try to add something else to your existing question. – jfriend00 Sep 28 '16 at 07:30