简体   繁体   中英

How to return promise to the router callback in NodeJS/ExpressJS

I am new to nodejs/expressjs and mongodb. I am trying to create an API that exposes data to my mobile app that I am trying to build using Ionic framework.

I have a route setup like this

router.get('/api/jobs', (req, res) => {
  JobModel.getAllJobsAsync().then((jobs) => res.json(jobs)); //IS THIS THe CORRECT WAY?
});

I have a function in my model that reads data from Mongodb. I am using the Bluebird promise library to convert my model functions to return promises.

const JobModel = Promise.promisifyAll(require('../models/Job'));

My function in the model

static getAllJobs(cb) {

    MongoClient.connectAsync(utils.getConnectionString()).then((db) => {

      const jobs = db.collection('jobs');
      jobs.find().toArray((err, jobs) => {

        if(err) {
          return cb(err);
        }

        return cb(null, jobs);
      });
    });
  }

The promisifyAll(myModule) converts this function to return a promise.

What I am not sure is,

  • If this is the correct approach for returning data to the route callback function from my model?
  • Is this efficient?
  • Using promisifyAll is slow? Since it loops through all functions in the module and creates a copy of the function with Async as suffix that now returns a promise. When does it actually run? This is a more generic question related to node require statements. See next point.
  • When do all require statements run? When I start the nodejs server? Or when I make a call to the api?

Your basic structure is more-or-less correct, although your use of Promise.promisifyAll seems awkward to me. The basic issue for me (and it's not really a problem - your code looks like it will work) is that you're mixing and matching promise-based and callback-based asynchronous code. Which, as I said, should still work, but I would prefer to stick to one as much as possible.

If your model class is your code (and not some library written by someone else), you could easily rewrite it to use promises directly, instead of writing it for callbacks and then using Promise.promisifyAll to wrap it.

Here's how I would approach the getAllJobs method:

static getAllJobs() {

    // connect to the Mongo server
    return MongoClient.connectAsync(utils.getConnectionString())

        // ...then do something with the collection
        .then((db) => {
            // get the collection of jobs
            const jobs = db.collection('jobs');

            // I'm not that familiar with Mongo - I'm going to assume that
            // the call to `jobs.find().toArray()` is asynchronous and only 
            // available in the "callback flavored" form.

            // returning a new Promise here (in the `then` block) allows you
            // to add the results of the asynchronous call to the chain of
            // `then` handlers. The promise will be resolved (or rejected) 
            // when the results of the `job().find().toArray()` method are 
            // known
            return new Promise((resolve, reject) => {
                jobs.find().toArray((err, jobs) => {
                    if(err) {
                        reject(err);
                    }
                    resolve(jobs);
                });
            });
        });
}

This version of getAllJobs returns a promise which you can chain then and catch handlers to. For example:

JobModel.getAllJobs()

    .then((jobs) => {
        // this is the object passed into the `resolve` call in the callback
        // above. Do something interesting with it, like
        res.json(jobs);
    })

    .catch((err) => {
        // this is the error passed into the call to `reject` above
    });

Admittedly, this is very similar to the code you have above. The only difference is that I dispensed with the use of Promise.promisifyAll - if you're writing the code yourself & you want to use promises, then do it yourself.

One important note: it's a good idea to include a catch handler. If you don't, your error will be swallowed up and disappear, and you'll be left wondering why your code is not working. Even if you don't think you'll need it, just write a catch handler that dumps it to console.log . You'll be glad you did!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM