0

I am trying to build and return an Object using Bluebird Promises. The Promise is a HTTP request which gets additional data to add to the Object.

I created a function that carries out a request in a for loop (I am also using a framework that carries out some middleware - this is what the z. is about)

const getWebAppCustomFieldDetails  = (z, url) => {
    const responsePromise = z.request({
        url:url,
        headers:{
          'content-type': 'application/json'
        }
     });
    return responsePromise
     .then(response =>{
      return JSON.parse(response.content);
     });
};

This function is called within the following code:

const webAppFields  = (z, bundle) => {
//This section carries creates an initial request which gets the bulk of the data
const responsePromise = z.request({
  url: webAppUrl(bundle) + '/' + encodeURI(bundle.inputData.webApp),
  headers:{
    'content-type': 'application/json'
  },
});
//This is an array to hold the objects created from the response
var fields = [];
return responsePromise
  .then(response => {

    response = JSON.parse(response.content);

    //From the response, append the core fields
    response.systemFields.forEach( function (systemField) {
      fields.push({
        'key': systemField.name,
        'required': systemField.required,
        'type': systemField.type.toLowerCase()
      });
    });
    return response;
  })  
  .then(response => {
    //Sometimes there are custom fields that need to be retrieved individually
    const customFieldCount = response.fields.length;
    var customFieldAppend = '';
    for (var i = 0; i < customFieldCount; i++){

      getWebAppCustomFieldDetails(z, response.fields[0].links[0].uri)
        .then(response =>{
          customFieldAppend = {
            'key': response.name,
            'required': response.required,
            'type': response.type.toLowerCase()
          };
          //This push doesn't updated the fields array!
          fields.push(customFieldAppend);
        });
    }
  //This return does not include the custom fields!
  return fields;
  });
};

I cannot figure out how to return the value from the nested Promise

OsulliP
  • 105
  • 1
  • 5

1 Answers1

0

You can use Promise.reduce to reduce the list of promises you are creating inside the for loop into a single promise:

...
    .then(response => {
        const customFieldCount = response.fields.length;
        var customFieldAppend = '';

        // Promice.reduce will return the accumulator "totalFields"
        return Promise.reduce(response.fields, (totalFields, field) => {
            getWebAppCustomFieldDetails(z, field.links[0].uri) // Using the "field" variable provided by the reducer function
                            .then(response => {
                                customFieldAppend = {
                                    'key': response.name,
                                    'required': response.required,
                                    'type': response.type.toLowerCase()
                                };
                                // Add the data to the accumulator "totalFields"
                                totalFields.push(customFieldAppend);
                            });
        }, []); // The third argument is the initial value of the accummulator. In your example it is a an array, so the initial value is an empty array.
    });
...

Promise.reduce takes in input three arguments: the list of arguments to loop on (response.fields), the reducer function and the initial value for the accumulator. The accumulator (which I called totalFields) is the first argument of the reducer function, it is the variable used to reduce the values in the list in a single value. In your case the accumulator is an array (the fields array used in your example) so its initial value is an empty array.

Inside the reduce function you can access the single elements of the list (second argument) and you can call your async operation and fill the accumulator ad every step. The Promise.reduce function will return the accumulator wrapped inside a promise. For this reason your function can directly returns the Promise.reduce's returned promise.

Andrea
  • 3,370
  • 1
  • 17
  • 25