JavaScript Node.js - How to chain Promise in The right way node chain promise,node promise chain error handling,node promise

I recently moved from callback functions to promises in node.js. I want to preform async query to the DB (psql) in the most elegant way. I was wondering if the following code is the right way to do it or if I can chain for example the promises in a way of first().then(second).then(third).

function queryAll(req, res) {
    searchQuery()
    .then((rows) => {
        console.log(rows);
        totalQuery()
        .then((total) => {
            console.log(total);
        });
    });
    res.json({"rows": rows, "total": total});
}

function searchQuery() {
    return new Promise(function(resolve, reject) {
        var rowData = { rows: {} };
        pool.query('select age, sex from workers;', values, function(err, result) {
            if(err) {
                return console.error('error running query', err);
                reject(err);
            }
            rowData.rows = result.rows;
            resolve(rowData);
        });
    });
}

function totalQuery() {
    return new Promise(function(reject, resolve) {
        var totalData = { totals: {} };
        pool.query('select sex, scores from workers group by sex;', values, function(err, result) {
            if(err) {
                return console.error('error running query', err);
                reject(err);
            }
            totalData.totals = result.rows;
            resolve(totalData);
        });
    });
}
Answer:1
var rowData = { rows: {} };
var totalData = { totals: {} };

First of all, these make no sense stored in variables since there's nothing else on the object. Just resolve with the rows directly instead.

return console.error('error running query', err);

Also, don't just console.log your errors. then accepts a second callback that executes on thrown errors or rejected promises. Throw this message in an error or reject with it instead. Also, I would leave logging to the consumer.

function queryAll(req, res) {
    searchQuery()
    .then((search) => {
        console.log(rows);
        totalQuery()
        .then((total) => {
            console.log(total);
        });
    });
    res.json({"rows": rows, "total": total});
}

rows and total don't exist anywhere. Plus, by the time res.json executes, rows and total (assuming they come from inside the callbacks) won't exist yet since the whole sequence is async. You'll get undefined values as results.

I see little point in running searchQuery and totalQuery in sequence as they're not dependent on each other. It's better to run them parallel instead. Use Promise.all for that.

function queryAll(req, res) {
  Promise.all([
    searchQuery(),
    totalQuery()
  ]).then(values => {
    const rows = values[0];
    const total = values[1];
    res.json({"rows": rows, "total": total});
  }, function(e){
    // something went wrong
  });
}

function searchQuery() {
  return new Promise(function(resolve, reject) {
    pool.query('select age, sex from workers;', values, function(err, result) {
      if(err) reject(err);
      else resolve(result.rows);
    });
  });
}

function totalQuery() {
  return new Promise(function(reject, resolve) {
    pool.query('select sex, scores from workers group by sex;', values, function(err, result) {
      if(err) reject(err);
      else resolve(result.rows);
    });
  });
}
Answer:2

You have a few issues in the code:

  • You return before executing reject()
  • There is an undefined rows variable (mismatch with search)
  • res.json is executed before the results are in.
  • The promises resolve to objects like { rows: rows }, but the main function seems to expect the plain numbers, not the objects. So let the promises just resolve to numeric values.
  • The second SQL is ambiguous since the second field is not aggregated and does not appear in the group by clause either. Assuming you want to sum the scores, use sum().
  • The second query is only launched after the first one has returned results, but this can be done in parallel
  • You have very similar code repeated. Try to reuse code and make the SQL statement an argument.

Here is how I would suggest to do it:

function queryAll(req, res) {
    return Promise.all([searchQuery(), totalQuery()]).then(([rows, total]) => {
        console.log('rows', rows);
        console.log('total', total);
        // Make sure to only access the promised values in the `then` callback
        res.json({rows, total});
    });
}

function searchQuery() {
    return promiseQuery('select age, sex from workers;');
}

function totalQuery() {
    // When you group, make sure to aggregate:
    return promiseQuery('select sex, sum(scores) as scores from workers group by sex;');
}

function promiseQuery(sql) { // reusable for other SQL queries
    return new Promise(function(resolve, reject) {
        pool.query(sql, values, function(err, result) {
            if(err) {
                // Do not return before calling reject!
                console.error('error running query', err);
                reject(err);
                return;
            }
            // No need for a variable or object, just resolve with the number of rows
            resolve(result.rows);
        });
    });
}
Answer:3

The most elegant solution would be via pg-promise:

function queryAll(req, res) {
    db.task(t => {
        return t.batch([
            t.any('SELECT age, sex FROM workers', values),
            t.any('SELECT sex, scores FROM workers GROUP BY sex', values)
        ]);
    })
        .then(data => {
            res.json({rows: data[0], total: data[1]});
        })
        .catch(error => {
            // handle error
        });
}

And that's everything. You don't have to reinvent promise patterns for working with the database, they are all part of the library already.

And if your queries have a dependency, see: How to get results from multiple queries at once.

Or if you prefer ES6 generators:

function queryAll(req, res) {
    db.task(function* (t) {
        let rows = yield t.any('SELECT age, sex FROM workers', values);
        let total = yield t.any('SELECT sex, scores FROM workers GROUP BY sex', values);
        return {rows, total};
    })
        .then(data => {
            res.json(data);
        })
        .catch(error => {
            // handle error
        });
}

And with the ES7's await/async it would be almost the same.

Answer:4

First of all there are some errors in your code, you have to place the reject before the return, otherwise it will be never called, and create a dangling promise:

function searchQuery() {
  return new Promise(function(resolve, reject) {
    var rowData = {
      rows: {}
    };

    pool.query('select age, sex from workers;', values, function(err, result) {
      if (err) {
        reject(err);
        console.error('error running query', err);
      } else {
        rowData.rows = result.rows;
        resolve(rowData);
      }
    });
  });
}

Beside that you should not nest the Promises when ever possible.

So it should be:

 function queryAll(req, res) {
   var result = {}; 
   searchQuery()
     .then((search) => {
       console.log(search);
       result.rows = search;
       return totalQuery();
     })
     .then((total) => {
       result.total = total;
       console.log(total);
     });
 }

The res.json has to be called in the then part of the Promise:

 function queryAll(req, res) {
   var result = {}; 
   searchQuery()
     .then((search) => {
       console.log(search);
       result.rows = search;
       return totalQuery();
     })
     .then((total) => {
       result.total = total;
       console.log(total);
     })
     .then(() => {
       res.json({
         "rows": result.rows,
         "total": result.total
       });
     });
 }

If your queryAll is called as e.g. middleware of express, then you should handle the catch case within queryAll:

 function queryAll(req, res) {
   var result = {}; 
   searchQuery()
     .then((search) => {
       console.log(search);
       result.rows = search;
       return totalQuery();
     })
     .then((total) => {
       result.total = total;
       console.log(total);
     })
     .then(() => {
       res.json({
         "rows": result.rows,
         "total": result.total
       });
     })
     .catch( err => {
        res.status(500).json({error: 'some error'})
     });
 }

For postgress I would suggest to use pg-promise instead of using a callback style library and wrapping it into promises yourself.

You could simplify the code if you use a library like bluebird:

 const bPromise = require('bluebird')

 function queryAll(req, res) {
   bPromise.all([
     searchQuery(),
     totalQuery()
   ])
   .spread((rows, total) => {
       res.json({
         "rows": rows,
         "total": total
       });
     })
     .catch(err => {
       res.status(500).json({
         error: 'some error'
       })
     });
 }
Answer:5

For websites that rely on Ajax or javascript to render data, how can I use WWW::Selenium to save the data? My following code was able to perform all the clicks and get to the correct webpage, however ...

For websites that rely on Ajax or javascript to render data, how can I use WWW::Selenium to save the data? My following code was able to perform all the clicks and get to the correct webpage, however ...

  1. website builder
  2. website design
  3. website maker
  4. website hosting
  5. website templates
  6. website checker
  7. website speed test
  8. website citation
  9. website builder free
  10. website name generator
  11. website down
  12. website unblocker
  13. website domain
  14. website apa citation
  15. website in spanish
  16. website archive
  17. websites like youtube
  18. website traffic
  19. website ideas
  20. websites like airbnb

I have a requirement in a username field where I have to validate the special characters but allow '.' dot character. We have custom method in plugin alphanumeric but it doesn't allow dot. please ...

I have a requirement in a username field where I have to validate the special characters but allow '.' dot character. We have custom method in plugin alphanumeric but it doesn't allow dot. please ...

  1. jquery validate plugin not working
  2. jquery validate plugin example
  3. jquery validate plugin cdn
  4. jquery validate plugin download
  5. jquery validate plugin tutorial
  6. jquery validate plugin before submit
  7. jquery validate plugin error message placement
  8. jquery validate plugin date format mm/dd/yyyy
  9. jquery validate plugin add rules dynamically
  10. jquery validate plugin select box
  11. jquery validate plugin float number
  12. jquery validate plugin
  13. jquery validate plugin email
  14. jquery validate plugin phone number
  15. jquery validate plugin rules
  16. jquery validate plugin regex
  17. jquery validate plugin documentation
  18. jquery validate plugin date
  19. jquery validate plugin checkbox
  20. jquery validate plugin submithandler

I am trying to create a Google Adwords script that can somehow exclude TODAY's date from the Date Range. According to Adwords documentation the general syntax is as follows: forDateRange("20130324", "...

I am trying to create a Google Adwords script that can somehow exclude TODAY's date from the Date Range. According to Adwords documentation the general syntax is as follows: forDateRange("20130324", "...

I have a problem with Google Map in React. Everything works great but, when I try to re-render other place in this map it doesnt work :( I mean when I change city (e.g. select) new props (latitude, ...

I have a problem with Google Map in React. Everything works great but, when I try to re-render other place in this map it doesnt work :( I mean when I change city (e.g. select) new props (latitude, ...

  1. react google component
  2. react component google maps
  3. react google calendar component
  4. react google login component github
  5. react-google-login-component
  6. react-google-places-component
  7. react google material component
  8. react js google maps component
  9. react native google maps component
  10. best react google map component
  11. npm react-google-login-component