async / await不会将构建的数组返回到父array.map()

问题描述 投票:0回答:3

在下面的代码中,expiringContentsAllBU填充在getOnlyContentWhatsNewReport内的async / await函数array.map()中,但expiringContentsAllBUbusinessUnits.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);
}
javascript node.js ecmascript-6 promise async-await
3个回答
2
投票

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
投票

由于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返回一个promise,而不是使用回调方法,你可以将这段代码更平坦一些。 async不会等待回调方法,所以请确保也返回一个承诺,否则此代码将无法正常等待。

完全承诺的版本重构了一点看起来像这样:

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
投票

你可以将你的.map()改为for loop

或者在你的.map()函数中,返回promises。然后你可以打电话给await Promise.all(promiseArray)


0
投票

使用与某些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);
}
© www.soinside.com 2019 - 2024. All rights reserved.