简体   繁体   中英

NodeJS promise (Q) .then its not called

im trying to do promises in NodeJS with mongodb queries.

Mongo library its mongod, i think it return promises.

This is my code:

var dbOrders = mongo(db.serverConfig.name + "/" + db.databaseName, ['orders']);
    var dbClients = mongo(db.serverConfig.name + "/" + db.databaseName, ['clients']);

    var promise;

    if (order.Order.Nif === "") {

        var newClient = {
            name: order.Order.Asegurado,
            ni: order.Order.Nif,//Never used..
            address: order.Order.Direccion,
            city: order.Order.Poblacion,
            province: order.Order.Provincia,
            phone: order.Order.Telefonos,
            cp: order.Order.CodigoPostal
        };

        promise = dbClients.clients.insert(newClient).then(function (currentClient) {
            log.debug('mondialParser', 'addClient', currentClient);
            dbOrders.orders.insert(order.Order).then(function (orderId) {
                log.debug('mondialParser', 'addOrder', orderId);
                dbClients.clients.update({_id: new ObjectID(currentClient)}, {$push: {dataOrders: orderId}}).then(function () {
                    log.debug('assignOrder', orderId, currentClient);
                });
            });
        });

        Q.fcall(promise);

Im trying to-> Insert client, then, insert order, then, assign the order _id to the client _id. I put the log.debug, but i can only see the

 log.debug('mondialParser', 'addClient', currentClient);

Other one its not called..Why? This is the correct use for promises? Is there any better way?

EDIT:

Other way:

var parseMondial = function (db, order, log) {

    "use strict";

    var dbOrders = mongo(db.serverConfig.name + "/" + db.databaseName, ['orders']);
    var dbClients = mongo(db.serverConfig.name + "/" + db.databaseName, ['clients']);

    if (order.Order.Nif === "") {

        var newClient = {
            name: order.Order.Asegurado,
            ni: order.Order.Nif,//Never used..
            address: order.Order.Direccion,
            city: order.Order.Poblacion,
            province: order.Order.Provincia,
            phone: order.Order.Telefonos,
            cp: order.Order.CodigoPostal
        };

        var insertClient = function () {
            dbClients.clients.insert(newClient).then(function (result) {
                log.debug('mondialParser', 'addClient', result);
                return result;
            });
        };

        var insertOrder = function () {
            dbOrders.orders.insert(order.Order).then(function(result) {
                log.debug('mondialParser', 'addOrder', result);
                return result;
            });
        };

        Q.all([insertOrder(), insertClient()]).spread(function (resultOrder, resultClient) {
            dbClients.clients.update({_id: new ObjectID(resultClient)}, {$push: {dataOrders: resultOrder}}).then(function () {
                log.debug('assignOrder', resultOrder, resultClient);
            });
        }).done();

    }
};

This execute all the "tasks" but inside w.all resultOrder and resultClient are undefined..

Both of your functions return undefined . You are returning the value from the .then handler correctly, but you are not returning a promise from insertOrder at all:

var insertClient = function () {
    // note the return
    return dbClients.clients.insert(newClient).then(function (result) {
        log.debug('mondialParser', 'addClient', result);
        return result;
    });
};

var insertOrder = function () {
    //note the return
    return dbOrders.orders.insert(order.Order).then(function(result) {
        log.debug('mondialParser', 'addOrder', result);
        return result;
    });
};

Q.all([insertOrder(),insertClient()]).spread(function(order,client){
     // access here
});

When Q.all gets a non promise argument (in this case undefined ) it casts it to a promise, so you got Q(undefined) twice there.

The core principle to keep in mind is that "a promise represents the result of an asynchronous operation". This means that it does not need to be executed, you simply need to wait for it to be fulfilled (or rejected). The operation is started as soon as you call the method, just like with synchronous code.

You may, however, wish to be aware that mongod uses the promise library, instead of Q. The two are interoprable though, so this will likely not cause any issues. If you want to turn a promise into a Q promise, you can just use var QPromise = Q(nonQPromise); .

You need to make sure you always keep returning promises from inside your onFulfilled functions (the ones passed as the first argument to .then ). With that in mind, I would re-write your original code as:

var dbOrders = mongo(db.serverConfig.name + "/" + db.databaseName, ['orders']);
var dbClients = mongo(db.serverConfig.name + "/" + db.databaseName, ['clients']);

var promise;

if (order.Order.Nif === "") {

  var newClient = {
    name: order.Order.Asegurado,
    ni: order.Order.Nif,//Never used..
    address: order.Order.Direccion,
    city: order.Order.Poblacion,
    province: order.Order.Provincia,
    phone: order.Order.Telefonos,
    cp: order.Order.CodigoPostal
  };

  promise = Q(dbClients.clients.insert(newClient).then(function (currentClient) {
    log.debug('mondialParser', 'addClient', currentClient);
    return dbOrders.orders.insert(order.Order).then(function (orderId) {
      log.debug('mondialParser', 'addOrder', orderId);
      return dbClients.clients.update({_id: new ObjectID(currentClient)}, {$push: {dataOrders: orderId}}).then(function () {
        log.debug('assignOrder', orderId, currentClient);
      });
    });
  }));

  // optionally call promise.done to expose any errors:
  promise.done(function () {
    log.debug('operations complete');
  }, function (err) {
    log.debug('operations failed ' + (err.stack || err));
  });
}

Note that promises, by default, do not expose their errors, because they can't know that the error will not be handle later. You can fix this by calling .done at the end of your promise chain, which indicates that you don't wish to handle any additional errors. Both Q and promise support this feature.

Your second example (which has the advantage of doing some of the work in parallel, can be fixed simply by adding a few extra return statements:

var parseMondial = function (db, order, log) {

  "use strict";

  var dbOrders = mongo(db.serverConfig.name + "/" + db.databaseName, ['orders']);
  var dbClients = mongo(db.serverConfig.name + "/" + db.databaseName, ['clients']);

  if (order.Order.Nif === "") {

    var newClient = {
      name: order.Order.Asegurado,
      ni: order.Order.Nif,//Never used..
      address: order.Order.Direccion,
      city: order.Order.Poblacion,
      province: order.Order.Provincia,
      phone: order.Order.Telefonos,
      cp: order.Order.CodigoPostal
    };

    var insertClient = function () {
      return dbClients.clients.insert(newClient).then(function (result) {
        log.debug('mondialParser', 'addClient', result);
        return result;
      });
    };

    var insertOrder = function () {
      return dbOrders.orders.insert(order.Order).then(function(result) {
        log.debug('mondialParser', 'addOrder', result);
        return result;
      });
    };

    Q.all([insertOrder(), insertClient()]).spread(function (resultOrder, resultClient) {
      return dbClients.clients.update({_id: new ObjectID(resultClient)}, {$push: {dataOrders: resultOrder}}).then(function () {
        log.debug('assignOrder', resultOrder, resultClient);
      });
    }).done();

  }
};

This can be further simplified though, by removing the extraneous functions:

var parseMondial = function (db, order, log) {

  "use strict";

  var dbOrders = mongo(db.serverConfig.name + "/" + db.databaseName, ['orders']);
  var dbClients = mongo(db.serverConfig.name + "/" + db.databaseName, ['clients']);

  if (order.Order.Nif === "") {

    var newClient = {
      name: order.Order.Asegurado,
      ni: order.Order.Nif,//Never used..
      address: order.Order.Direccion,
      city: order.Order.Poblacion,
      province: order.Order.Provincia,
      phone: order.Order.Telefonos,
      cp: order.Order.CodigoPostal
    };

    var resultOrderPromise = dbOrders.orders.insert(order.Order).then(function (result) {
      log.debug('mondialParser', 'addOrder', result);
      return result;
    });

    var resultClientPromise = dbClients.clients.insert(newClient).then(function (result) {
      log.debug('mondialParser', 'addClient', result);
      return result;
    });


    Q.all([resultOrderPromise, resultClientPromise]).spread(function (resultOrder, resultClient) {
      return dbClients.clients.update({_id: new ObjectID(resultClient)}, {$push: {dataOrders: resultOrder}}).then(function () {
        log.debug('assignOrder', resultOrder, resultClient);
      });
    }).done();

  }
};

This still executes both inserts in parallel because each insert is started before we wait for anything. Calling an asynchronous function starts the operation, and returns a promise for the result.

If you'd like a more complete tutorial for how promises work, check out: https://www.promisejs.org/

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