0

I am trying to create an array called pw_array, assign the contents of pw_subscribers to that array, then append each object in the pw_array with new key value pairs from the second promise. I am new to promises and having a lot of trouble making this work. Right now when I console.log(pw_customer) inside the second promise, inside the getCustomers function, it is returning what I want. But when I console.log(pw_array) later it is the original array.

var pw_array = [];
//first promise is working correctly
var getPaywhirlSubscribers = new Promise(function(resolve, reject) {

paywhirl.Subscriptions.getsubscribers({limit:100}, function(error, pw_subscribers) {
        Promise.all(JSON.parse(pw_subscribers).forEach(function(pw_subscriber) {
             pw_array.push(pw_subscriber);
        }))
        // console.log(pw_array);
        return resolve(pw_array);
    });
});

var getGatewayReferences = function(pw_array) {
    return new Promise(function(resolve, reject) {
        Promise.all(pw_array.forEach(function(pw_customer) {
            paywhirl.Customers.getCustomer(pw_customer.customer_id, function(error, customer) {
                pw_customer.phone = customer.phone;
                pw_customer.address = customer.address;
                pw_customer.gateway_reference = customer.gateway_reference;
                // this console.log is returning what I want
                // console.log(pw_customer);
            }); 
        }));
        resolve(pw_array);
        // console.log(pw_array);
    });
};

and the promise chain...

getPaywhirlSubscribers.then(getGatewayReferences).then(function(pw_array) {
  // this console.log is returning the original pw_array with pw_subscribers but not with the appended pw_customer keys
  console.log(pw_array);
});
2
  • 1
    Have you tried to use pw_array.map instead of pw_array.forEach, and for the map return the paywhirl.Customers.getCustomer(... (which I assume makes a promise). This way the next .then will have all the customers. Commented Nov 28, 2017 at 14:30
  • 1
    @asosnovsky is correct you are only mutating each item in the pw_array given to you by the forEach. Those items are not "connected live" to the original pw_array at that time. You should use .map Commented Nov 28, 2017 at 14:38

1 Answer 1

2

All of your code can be reduced to

var getPaywhirlSubscribers = function() {
  return new Promise(function(res, rej) {
    paywhirl.Subscriptions.getSubscribers({limit:100}, function(err, subs) {
      if (err) {
        rej(err);
      } else {
        res(JSON.parse(subs));
      }
    });
  });
};

var gatewayRefs = function(promiseOfArray) {
  return promiseOfArray.then(function(subs) {
    return Promise.all(subs.map(function(sub) {
      return new Promise(function(res, rej) {
        paywhirl.Customers.getCustomer(sub.customer_id, function(err, customer) {
          if (err) {
            rej(err);
          } else {
            res(Object.assign({}, sub, customer);
          }
        });
      });
    });
  });
};

gatewayRefs(getPaywhirlSubscribers()).then(function(arrayOfCustomers) {
  // do something with the customer array
});

Note that you can make this even shorter/simpler if you use one of the many utilities available to automatically convert node.js-style error -first callback APIs into Promise-based ones. Search for 'promise denodeify'.

You could also conceivably pull some of the steps out into a .then chain to reduce nesting, but that's as much aesthetic as practical IMHO.

Sign up to request clarification or add additional context in comments.

1 Comment

@David no problem. Just remember that you can't 'unbox' a Promise (like putting the values in an external array). You have to deal with the data only in a .then handler. Just keep chaining.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.