async / await не возвращает встроенный массив в родительский array.map () - PullRequest
0 голосов
/ 24 апреля 2019

В следующем коде expiringContentsAllBU заполняется в функции асинхронного ожидания / ожидания getOnlyContentWhatsNewReport, которая находится внутри array.map(), но expiringContentsAllBU становится пустым при доступе к ней вне функции businessUnits.map().

const getExpiringContents = async () => {
  let businessUnits = Object.keys(contentFulSpaces);  
  let expiringContentsAllBU = [];
  businessUnits.map( async (bu) => {
      await getOnlyContentWhatsNewReport(bu, (err, result) => { 
        if(result) {
          let expiringContentsByBU = {};
          expiringContentsByBU['businessUnit'] = bu;
          expiringContentsByBU['expiringContents'] = result;
          expiringContentsAllBU.push(JSON.parse(JSON.stringify(expiringContentsByBU)));
        } else console.log('No expiring contents found for WhatsNewSection');
      })
    });
    console.log('result', expiringContentsAllBU);
}

Ответы [ 4 ]

2 голосов
/ 24 апреля 2019

var getOnlyContentWhatsNewReport = Promise.resolve(123);

const getExpiringContents = async () => {
  let businessUnits = [{ id: 1 }, { id: 2 }, { id: 3 }];  
  const expiringContentsAllBU = await Promise.all(businessUnits.map(async (bu) => {
      return getOnlyContentWhatsNewReport.then(respBu => {
        bu.businessUnit = respBu;
        return bu;
      }).catch((err) => {
        console.log('No expiring contents found for WhatsNewSection');
        return null;
      });
   }));
   console.log('result', expiringContentsAllBU);
}

getExpiringContents();

Вам нужно подождать, пока карта не завершится и все обратные вызовы не будут выполнены. console.log и последующие кодовые блоки будут выполнены до завершения вашей карты, поэтому

const getExpiringContents = async () => {
  let businessUnits = Object.keys(contentFulSpaces);  
  const expiringContentsAllBU = await Promise.all(businessUnits.map(async (bu) => {
      return getOnlyContentWhatsNewReport(bu, (err, result) => { 
        if(result) {
          let expiringContentsByBU = {};
          expiringContentsByBU['businessUnit'] = bu;
          expiringContentsByBU['expiringContents'] = result;
          return JSON.parse(JSON.stringify(expiringContentsByBU);
        } else {
          console.log('No expiring contents found for WhatsNewSection');
          return null;
        }
      })
   }));
   console.log('result', expiringContentsAllBU);
}
1 голос
/ 24 апреля 2019

Поскольку map не знает об асинхронных функциях, вам нужно использовать что-то, что есть. Одним из примеров является Bluebird Promise.map эквивалент:

const getExpiringContents = async () => {
  let businessUnits = Object.keys(contentFulSpaces);  

  // Use Promise.map here to convert each businessUnit entry into a record
  let expiringContentsAllBU = await Promise.map(businessUnits, async (bu) => {
    await getOnlyContentWhatsNewReport(bu, (err, result) => { 
      if (!result) {
        console.log('No expiring contents found for WhatsNewSection');
        return;
      }

      let expiringContentsByBU = {};
      expiringContentsByBU['businessUnit'] = bu;
      expiringContentsByBU['expiringContents'] = result;

      return JSON.parse(JSON.stringify(expiringContentsByBU));
    })
  });

  // As this may contain undefined elements, remove those
  expiringContentsAllBU = expiringContentsAllBU.filter(e => e);

  console.log('result', expiringContentsAllBU);
}

Вы могли бы сгладить этот код немного больше, если бы вы заставили getOnlyContentWhatsNewReport вернуть обещание, как и должно, вместо использования метода обратного вызова. async не будет ждать методов обратного вызова, поэтому убедитесь, что также возвращает обещание, или этот код не будет ждать правильно.

A полностью обещанная версия, которая подверглась рефакторингу, выглядит примерно так:

const getExpiringContents = async () => {
  let businessUnits = Object.keys(contentFulSpaces);  

  let expiringContentsAllBU = await Promise.map(businessUnits, async businessUnit => {
    let expiringContents = await getOnlyContentWhatsNewReport(businessUnit);

    if (!expiringContents) {
      console.log('No expiring contents found for WhatsNewSection');
      return;
    }

    // Choosing names that match the output means you can use the destructuring operator
    let expiringContentsByBU = {
      businessUnit,
      expiringContents
    };

    // A more formalized "clone" function could help here.
    return JSON.parse(JSON.stringify(expiringContentsByBU));
  });

  // As this may contain undefined elements, remove those
  expiringContentsAllBU = expiringContentsAllBU.filter(e => e);

  console.log('result', expiringContentsAllBU);
}
0 голосов
/ 27 мая 2019

Использование async с некоторой функцией lodash для здравомыслия поможет -

getExpiringContents = async() => {
  let businessUnits = Object.keys(contentFulSpaces);

  let expiringContentsAllBU = await Promise.map(businessUnits, async businessUnit => {
    let expiringContents = await getOnlyContentWhatsNewReport(businessUnit);

    if (_.isEmpty(expiringContents)) {
      console.log('No expiring contents found for WhatsNewSection');
      return;
    }

    // Choosing names that match the output means you can use the destructuring operator
    let expiringContentsByBU = {
      businessUnit,
      expiringContents
    };

    // A more formalized "clone" function could help here.
    return _.cloneDeep(expiringContentsByBU);
  });

  // As this may contain undefined elements, remove those
  expiringContentsAllBU = _.compact(expiringContentsAllBU);

  console.log('result', expiringContentsAllBU);
}
0 голосов
/ 24 апреля 2019

Вы можете изменить .map() на for loop.

Или в вашей функции .map() верните обещания. Тогда вы можете позвонить await Promise.all(promiseArray)

...