Использование Bluebird Promise в цикле For для создания и возврата массива объектов

Я пытаюсь создать и вернуть объект, используя обещания Bluebird. Обещание — это HTTP-запрос, который получает дополнительные данные для добавления к объекту.

Я создал функцию, которая выполняет запрос в цикле for (я также использую фреймворк, который выполняет некоторое промежуточное программное обеспечение — это то, о чем z.)

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

Эта функция вызывается в следующем коде:

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;
  });
};

Я не могу понять, как вернуть значение из вложенного промиса


person OsulliP    schedule 28.07.2017    source источник


Ответы (1)


Вы можете использовать Promise.reduce, чтобы сократить список промисов, которые вы создаете внутри цикл for в одно обещание:

...
    .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 принимает на вход три аргумента: список аргументов для цикла (response.fields), функцию reducer и начальное значение для аккумулятора. Аккумулятор (который я назвал totalFields) — это первый аргумент функции reducer, это переменная, используемая для сведения значений в списке к одному значению. В вашем случае аккумулятор представляет собой массив (массив fields, используемый в вашем примере), поэтому его начальное значение представляет собой пустой массив.

Внутри функции reduce вы можете получить доступ к отдельным элементам списка (второй аргумент), и вы можете вызвать свою асинхронную операцию и заполнить объявление аккумулятора на каждом шагу. Функция Promise.reduce вернет аккумулятор, заключенный в промис. По этой причине ваша функция может напрямую возвращать обещание Promise.reduce.

person Andrea    schedule 02.08.2017