简体   繁体   中英

Node.js Promise Chain with API and database query

I am pretty new to the whole promises business and am trying out my project with them.
No I need to query an external API, go several items in the response, do other checks on my own database with them and when all of them are finished, need to resolve the whole promise in itself.
I also need even another call to my database at the marked point with another promise. These are independent from each other but the "parent" promise should only resolve when both are resolved.
I am at a wall here and probably need some general explanation about chaining several promises with multiple items.
Maybe I just understand something generally wrong here... Here is my code so far (shortened at ...):

'use strict';

import rp from 'request-promise';
import _ from 'lodash';

var Import = {
  init: function(user, options) {
    return new Promise((resolve, reject) => {
      rp.get("...") // call to external API
        .then((res) => {
          ...
          resolve();
        });
      ...
    });
  },
  run: function() {
    return new Promise((resolve, reject) => {
      ...

      rp.get(...) // call to external API
        .then((res) => {
          var events = JSON.parse(res).data;
          var promises = [];

          for (var i = 0; i < events.length; i++) {

            promises.push(new Promise((resolve, reject) => {
              ...

              Location.findOneAndUpdateAsync(...)
                .then((loc) => {
                  events[i].location = loc._id;
                  resolve();
                })
                .catch((err) => {
                  console.error(err);
                  reject();
                });

              // I need even another call to my database here later with another promise
            }));
          }
          return Promise.all(promises)
            .then(() => {
              console.log("all promises resolved");
              resolve(events);
            });
        })
        .catch((err) => {
          console.error(err);
          reject(err);
        });
    });
  }
};

You can dramatically simplify your code by not falling foul of the Promise constructor anti-pattern - the functions you're calling already return promises so you should take advantage of those.

Then, eliminate the for / push loop with Array.prototype.map :

var promises = events.map(function(event) {
    return Location.findOneAndUpdateAsync(...)
            .then((loc) => event.location = loc._id);
});

You said you have two sets of calls to make, but as they're independent, you might as well just use another .map call:

var promises2 = events.map(function(event) {
    return ...
});

and then you just need to wait for all of those and return your events object:

return Promise.all(promises.concat(promises2)).then(() => events);

There's no need for all those .catch blocks - you should let the error propagate upwards.

If (per your comments) the two inner calls have a dependency, you could try this:

var promises = events.map(function(event) {
    return Location.findOneAndUpdateAsync(...)
           .then((loc) => {
               event.location = loc._id;
               if (condition) {
                   return XXXOtherFunctionReturningPromise();
               }
           });
});

[and obviously then eliminate the .concat call from above]

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