Javascript 数组在异步函数中将元素推入数组后打印为空

Javascript 数组在异步函数中将元素推入数组后打印为空,javascript,asynchronous,async-await,promise,Javascript,Asynchronous,Async Await,Promise,我是async/await的新手。当我调用函数时,第一个console.log(newArr)打印数组元素,但第二个是空数组,当我返回也是空的数组时。谁能帮帮我,我哪里出错了 const prefixPM = 'PM'; const decryptComment = (comment) => { const data = decrypt(comment).then(function (result) { const buf2 = Buff

我是async/await的新手。当我调用函数时,第一个console.log(newArr)打印数组元素,但第二个是空数组,当我返回也是空的数组时。谁能帮帮我,我哪里出错了

const prefixPM = 'PM';
    const decryptComment = (comment) => {
          const data = decrypt(comment).then(function (result) {
            const buf2 = Buffer.from(result, 'base64').toString('ascii');
            return buf2;
          });
          return data;
        };
    
const pmData = await queryInterface.sequelize.query(
      `select ram.id, ra.name from rater_attributes ra
      inner join rater_attribute_mappings ram
      on ra.id = ram.raterAttributeId
      inner join attributes a
      on a.id = ram.by
      where a.name='Project Manager'`,
      { raw: true, type: Sequelize.QueryTypes.SELECT },
    );

const createPMAttributes = (ratingId, rating) => {
      const newArr = [];
      pmData.map(async (data) => {
        const attribute = `${prefixPM}${data.name}`;

        let pmComment = rating.PMComment
          ? await decryptComment(rating.PMComment)
          : null;
        pmComment = JSON.parse(pmComment);
        newArr.push({
          ratingId: ratingId,
          raterAttributeMappingId: data.id,
          rating: rating[`${attribute}`],
          comment:
            pmComment && pmComment[`${attribute}Comment`] ? pmComment[`${attribute}Comment`] : null,
          createdAt: rating.createdAt,
          updatedAt: rating.updatedAt,
        });
      console.log(newArr) -- this prints the newArr elements
      });
      console.log(newArr); -- this prints empty arr
return newArr 
    };
.map()
不支持异步,因此它会并行运行循环的所有迭代,在点击
wait
后立即开始第二次迭代)。因此,您的第二个
console.log()
正在尝试在任何回调完成之前以及在它们将数据放入
newArr
之前记录
newArr

下面是事情发生的顺序

  • 您可以调用
    pmData.map()
  • 它获取
    pmData
    数组中的第一个元素并调用回调函数
  • 回调不会等待decryptComment(…),这会导致回调暂停并立即返回承诺
  • .map()
    .map()
  • .map()
    然后获取
    pmData
    数组中的下一个值并再次调用回调,即使第一个值仍在等待
    wait decryptComment()
  • 因此,您最终将并行运行所有这些调用,并且您的
    .map()
    将在任何回调完成之前完成

    解决方案是在返回的承诺数组上使用
    await Promise.all()
    ,如果希望这些承诺并行运行,或者切换到
    for
    循环,当点击
    await
    时,循环将暂停

    这里有一个解决方案,同时仍然并行运行所有调用。这将返回解析为值数组的承诺

    const createPMAttributes = (ratingId, rating) => {
        return Promise.all(pmData.map(async (data) => {
            const attribute = `${prefixPM}${data.name}`;
    
            let pmComment = rating.PMComment ?
                await decryptComment(rating.PMComment) :
                null;
            pmComment = JSON.parse(pmComment);
            return {
                ratingId: ratingId,
                raterAttributeMappingId: data.id,
                rating: rating[`${attribute}`],
                comment: pmComment && pmComment[`${attribute}Comment`] ? pmComment[
                    `${attribute}Comment`] : null,
                createdAt: rating.createdAt,
                updatedAt: rating.updatedAt,
            };
        }));
    };
    
    下面是一个使用
    for
    循环的解决方案,该循环按顺序运行操作:

    const createPMAttributes = async (ratingId, rating) => {
        const newArr = [];
        for (let data of pmData) {
            const attribute = `${prefixPM}${data.name}`;
    
            let pmComment = rating.PMComment ?
                await decryptComment(rating.PMComment) :
                null;
            pmComment = JSON.parse(pmComment);
            newArr.push({
                ratingId: ratingId,
                raterAttributeMappingId: data.id,
                rating: rating[`${attribute}`],
                comment: pmComment && pmComment[`${attribute}Comment`] ? pmComment[
                    `${attribute}Comment`] : null,
                createdAt: rating.createdAt,
                updatedAt: rating.updatedAt,
            });
        }
        return newArr;
    };
    

    这里有一个一般提示。仅当您实际想要使用它生成的返回数组时才使用
    .map()
    。如果您要做的只是使用它来迭代数组,那么请改用
    for
    循环,因为它更灵活并且是
    异步的


    而且,如果因为使用了
    wait
    ,而将
    .map()
    回调为
    async
    ,那么您将并行运行所有操作,并且知道何时完成的唯一方法是对回调生成的承诺数组使用
    Promise.all()
    。请记住,每个
    async
    函数都会返回一个承诺-始终。因此,
    让resultArr=someArr.map(async=>{}{}})
    将始终生成一个承诺数组,告诉您事情实际完成的时间。

    谢谢您的回答。我做了更改,但是当我调用函数const arr=wait createPMAttributes(pmRatingId,rating)时;控制台日志(arr);它打印[undefined,undefined,undefined,undefined,undefined,undefined],而不是数组elements@habiba-看起来我的版本中没有所有的更改。如果您使用的是我的第一个版本,那么请查看我的
    return
    在哪里。非常感谢!你是最棒的!它就像一个符咒但我有两个函数,一个用于PMattributes,另一个用于archAttributes,我想把这两个函数的评级推到一个arr中,然后遍历该数组并将对象插入数据库,你知道我怎么做吗?@habiba-我不明白。您想将两个函数合并为一个生成一个结果的函数,还是有两个单独的函数,从每个函数中得到一个结果数组,然后将这两个数组合并?仅供参考,这听起来有点像一个新问题。