-1

I would like to retrieve the result of a series of promises below and store it into a variable, so that I could use it outside of this chain. That being said, I keep on getting errors or the variable comes out as undefined.

Here's the series:

I've tried storing the promises in a variable i.e. var customerToken = //the code below. But, customerToken comes out as undefined, since the promises end after the variable is set.

var Stripe = StripeAPI('sk_test_key');

Stripe.customers.create({
  email: Meteor.user().emails[0].address,
  description: "SIDIM 2016",
  source: stripeToken
}).then(function(customer) {

  return Stripe.tokens.create({
    customer: customer.id
  }, {stripe_account: "acct_XXXYYYZZZ"});

}).then(function(token) {

  console.log(token);

  var charge = Stripe.customers.create({
    email: Meteor.user().emails[0].address,
    description: "SIDIM 2016",
    source: token.id
  }, {stripe_account: "acct_XXXYYYZZZ"});

  console.log(charge);

}).then(function(charge) {

  return Stripe.charges.create({
    amount: total,
    currency: 'usd',
    customer: charge.id
  }, {stripe_account: "acct_XXXYYYZZZ"});

}).catch(function(err) {
  // Deal with an error
});
mido
  • 24,198
  • 15
  • 92
  • 117
Nima Amin
  • 92
  • 2
  • 10
  • 2
    Which variable are you trying to store? No value is returned from second `.then()` – guest271314 Apr 13 '16 at 03:00
  • I would like to store the customer.id in the first return and the charge.id in the last one. The second one doesn't have a return because of my sad attempt to store the result in a variable. – Nima Amin Apr 13 '16 at 03:01
  • Do you want to store the `customer.id` outside of `Stripe.tokens.create({` call? Or, after the return value from `Stripe.tokens.create({` ? – guest271314 Apr 13 '16 at 03:03
  • I would like to store it outside of the entire thing, so that I can insert it into the DB in a separate function and use it later on. – Nima Amin Apr 13 '16 at 03:05
  • Possible duplicate of [How do I access previous promise results in a .then() chain?](http://stackoverflow.com/questions/28250680/how-do-i-access-previous-promise-results-in-a-then-chain) – mido Apr 13 '16 at 03:10
  • @NimaAmin take a look at Bergi's Mutable contextual state answer to the above question – mido Apr 13 '16 at 03:12

2 Answers2

0

You can return the values from each .then(), access values at .then() after chain

var customerTokens = Promise.resolve()
.then(function() {
    // do stuff
    var customerId = 1;
    return customerId; // return `customerId` here
})
.then(function(id) {
    // do stuff
    return id // return `id` : `customerId` here
})
.then(function(id) {
    // do stuff
    var chargeId = 2;
    return [id, chargeId]; // return both `customerId`:`id` and `chargeId`
})
.catch(function(err) {

});

customerTokens
.then(function(ids) {
    console.log(ids) // access `customerId`, `chargeId` here
});

Alternatively, if Stripe methods are also returned from .then() with customer.id , charge.id, you could pass Stripe method to a function that pushes both Promise values returned by Stripe methods and customer.id, charge.id to an array, where both Promise values returned from Stripe methods and individual charge.id and customer.id will be available at .then() chained to customerTokens.

var arr = [
  [],
  []
];

var Stripe = function(val) {
  return new Promise(function(resolve) {
    var d = Math.random() * 3000;
    setTimeout(function() {
      arr[0].push({
        StripeData: d // `Stripe` method data
      });
      if (val) {
        arr[1].push(val)
      }
      resolve(arr)
    }, d)
  })
}

var customerTokens = Promise.resolve()
.then(function() {
    // do stuff
    var customerId = 1;
    return Stripe({
      customerId: customerId
    }); // pass `customerId` here
})
.then(function(id) {

    // do stuff
    return Stripe() //
})
.then(function(id) {
    // do stuff
    var chargeId = 2;
    return Stripe({
      chargeId: chargeId
    }); // pass `customerId`
})
.catch(function(err) {

});

customerTokens
.then(function(data) {
    var ids = data[1];
    // access `customerId`, `chargeId` here at `data[1]`
    console.log("complete", data, JSON.stringify(ids))
});

You could also utilize Promise.all() , filter all results at single .then()

var arr = [
  [],
  []
];

var Stripe = function(val) {
  return new Promise(function(resolve) {
    var d = Math.random() * 3000;
    setTimeout(function() {
      arr[0].push({
        StripeData: d // `Stripe` method data
      });
      if (val) {
        arr[1].push(val)
      }
      resolve(arr)
    }, d)
  })
}

var customerTokens = Promise.all([Stripe({
      customerId: Math.random() * 10
    }), Stripe(), Stripe({
      chargeId: Math.random() * 5
    }).then(function(data) {
  // do stuff
  console.log(data);
  return data // return data
})])

.catch(function(err) {

});

customerTokens
.then(function(data) {
    data.forEach(function(response, index) {
      response[1].forEach(function(ids) {
        console.log(ids) // filter `customerId`, `chargeId` 
      })
    })
});
guest271314
  • 1
  • 15
  • 104
  • 177
  • but how would this work if your chain returns a promise? – mido Apr 13 '16 at 03:16
  • @mido _"but how would this work if your chain returns a promise?"_ Not following? – guest271314 Apr 13 '16 at 03:18
  • you are returning values at each step of chain, how would you pass the `id` variable if you return promise? – mido Apr 13 '16 at 03:19
  • @mido _"you are returning values at each step of chain, how would you pass the id variable if you return promise?"_ Return which `Promise` ? See comment at _"The second one doesn't have a return because of my sad attempt to store the result in a variable."_ . Though, if OP is actually returning `Stripe` method call to chained `.then()`, can `return` `Promise.all([Stripe.method(), customer.id])` with `customer.id` , `charge.id` included as parameters; filter results at `customerTokens.then()` – guest271314 Apr 13 '16 at 03:22
0

the ugly yet simple solution would be to use (kinda) global variables:

var customerId;

Stripe.customers.create({...}).then(function(customer){
    customerId = customer.id;
    ...

a more elegant way would be to use context, and pass it as this attribute throught the promise chain:

function getExample() {
    var ctx = {};
    return promiseA(…)
    .then(function(resultA) {
        this.resultA = resultA;
        // some processing
        return promiseB(…);
    }.bind(ctx)).then(function(resultB) {
        // more processing
        return // something using both this.resultA and resultB
    }.bind(ctx));
}

read more details about this solution in Bergi's answer

best way to do this might be using async promises, but then you might have to wait till ES7:

var customer = await Stripe.customers.create({...});
Community
  • 1
  • 1
mido
  • 24,198
  • 15
  • 92
  • 117