简体   繁体   中英

JS Promises - End of Chain Returning before Chain Step

I have a promise chain that consists of database queries and API calls. I am trying to run these processes and then store them as objects that I can use in my views, but it appears that my chain is rendering the last step faster than the value can be pulled from the stripe.customers.retrieve portion, which is preventing me from restoring the object returned by that method. See terminal output section for example. It might be my misunderstanding of Promises, but shouldn't chaining call the items in a top to bottom order? Is there a way to prevent the last chain from rendering before the stripe.customers.retrieve finishes?

Promise chain:

var account;
var card;
var customerInfo;
var test;

models.Account.findOne({
    ...
}).then(function(_account){
    console.log('Here is the account: ' + _account);
    account = _account;
    return stripe.customers.retrieveCard(account.customerId, account.cardId, {
        function(err, account){
            if (err){
                return console.log(err);
            } else {
                return console.log(account);
            }
        }
    }).then(function(_card){
        console.log('Here is the card: ' + _card);
        card = _card;
        return stripe.customers.retrieve(account.customerId, function(err, customer){
            if (err){
                return console.log(err);
            } else {
                return console.log('Customer is returned ' + customer)
            }
        }).then(function(_customer){
            customerInfo = _customer;
            console.log('Returned value ' + _customer);
            console.log('Current card' + card);
            console.log('Current customer ' + customerInfo);
            res.render('pages/app/settings-billing.hbs', {
                ...
            });
        });
    });
}).catch(function(err){
    console.log(err);
});

Terminal Output:

Here is the account: [object SequelizeInstance:account]
Here is the card: [object Object]
Returned value undefined
Current card[object Object]
Current customer undefined
Customer is returned [object Object]

Here is the answer: You need to call your promises in the way you are expecting your return values. What you were doing wrong is that you have nesting promises. The idea behind is that you invoke a promise and when it's fulfilled resolve the value.

models.Account.findOne({
    ...
})
.then(function(_account){
    console.log('Here is the account: ' + _account);
    account = _account;

    return stripe.customers.retrieveCard(account.customerId, account.cardId, {
        function(err, account){
            if (err){
                return console.log(err);
            } else {
                return console.log(account);
            }
        }
    });
})
.then(function(_card){
     console.log('Here is the card: ' + _card);
     return stripe.customers.retrieve(account.customerId, function(err, customer){
         if (err){
                return console.log(err);
            } else {
                return console.log('Customer is returned ' + customer)
            }
        });
})
.then(function(_customer){  
                customerInfo = _customer;
            console.log('Returned value ' + _customer);
            console.log('Current card' + card);
            console.log('Current customer ' + customerInfo);
            res.render('pages/app/settings-billing.hbs', {
                ...
            });
}).catch(function(err){
    console.log(err);
});

Use then() on each stripe method instead of callback so you return a promise from each.

Have modified this a bit to keep passing one object through to the end instead of using global variables

models.Account.findOne({
    ...
  })
  .then(function(_account) {
    let data = {
      account: _account
    }
    return stripe.customers.retrieveCard(_account.customerId, _account.cardId).then(function(card) {          
      data.card = card;
      return data;
    });
  })
  .then(function(data) {
    console.log('Here is the card: ' + data.card);
    return stripe.customers.retrieve(data.account.customerId).then(function(customer) {
      data.customer = customer;
      return data
    });
  })
  .then(function(data) {
    console.log(JSON.stringify(data, null, ' '));

  }).catch(function(err) {
    console.log(err);
  });

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