嵌套的Promise.all异步/等待地图

时间:2020-06-16 20:35:50

标签: javascript asynchronous promise async-await

我遇到了一个嵌套的for循环,其中包含等待操作,如下所示:

    async handleProjects (projects) {
        for (let i = 0; i < projects.rows.length; i++) {
            projects.rows[i].owner = await this.userProvider.serialize(projects.rows[i].owner);
            for (let j = 0; j < projects.rows[i].collaborators.length; j++) {
                const collaborator = await this.userProvider.serialize(projects.rows[i].collaborators[j].email);
                if (collaborator) {
                    projects.rows[i].collaborators[j].name = collaborator.name;
                    delete projects.rows[i].collaborators[j].role;
                }
            }
        }
        return projects;
    }

1。 上面的代码按顺序正确运行?

2。 为了提高性能,我想使用promise.all,如下所示,但是一些运行时间大致相同,有时promise.all甚至更长。我在这方面的错误在哪里?

    async handleProject (projects) {
        await Promise.all(projects.rows.map(async (row) => {
            console.log(row);
            row.owner = await this.userProvider.serialize(row.owner);
            return await Promise.all(row.collaborators.map(async (collaborator) => {
                const collaboratorObj = await this.userProvider.serialize(collaborator.email);
                if (collaboratorObj) {
                    collaborator.name = collaboratorObj.name;
                    delete collaborator.role;
                }
            }));
        }));
        return projects;
    }

1 个答案:

答案 0 :(得分:1)

让我们使用超时来模拟您的异步调用。

此代码与您进行优化之前的第一个示例等效。请注意,在任何给定时刻,仅存在一个未完成的承诺:

let serializeAndCache = owner => {
  console.log(`Starting: ${owner}`);
  let prm = new Promise(r => setTimeout(r, 2000));
  prm.then(() => console.log(`Finished: ${owner}`));
  return prm;
};

let project = {
  rows: [
    {
      owner: 'owner1',
      collaborators: [
        { name: null, email: 'collab1@row1.com' },
        { name: null, email: 'collab2@row1.com' },
        { name: null, email: 'collab3@row1.com' },
        { name: null, email: 'collab4@row1.com' }
      ]
    },
    {
      owner: 'owner2',
      collaborators: [
        { name: null, email: 'collab1@row2.com' },
        { name: null, email: 'collab2@row2.com' },
        { name: null, email: 'collab3@row2.com' },
        { name: null, email: 'collab4@row2.com' }
      ]
    },
    {
      owner: 'owner3',
      collaborators: [
        { name: null, email: 'collab1@row3.com' },
        { name: null, email: 'collab2@row3.com' },
        { name: null, email: 'collab3@row3.com' },
        { name: null, email: 'collab4@row3.com' }
      ]
    }
  ]
};

(async () => {
  for (let row of project.rows) {
    row.owner = await serializeAndCache(row.owner);
    for (let collaborator of row.collaborators) {
      let c = await serializeAndCache(collaborator.email);
      if (!c) continue;
      collaborator.name = c.name;
      delete collaborator.role;
    }
  }
})();

此代码等效于您的优化版本:

let serializeAndCache = owner => {
  console.log(`Starting: ${owner}`);
  let prm = new Promise(r => setTimeout(r, 2000));
  prm.then(() => console.log(`Finished: ${owner}`));
  return prm;
};

let project = {
  rows: [
    {
      owner: 'owner1',
      collaborators: [
        { name: null, email: 'collab1@row1.com' },
        { name: null, email: 'collab2@row1.com' },
        { name: null, email: 'collab3@row1.com' },
        { name: null, email: 'collab4@row1.com' }
      ]
    },
    {
      owner: 'owner2',
      collaborators: [
        { name: null, email: 'collab1@row2.com' },
        { name: null, email: 'collab2@row2.com' },
        { name: null, email: 'collab3@row2.com' },
        { name: null, email: 'collab4@row2.com' }
      ]
    },
    {
      owner: 'owner3',
      collaborators: [
        { name: null, email: 'collab1@row3.com' },
        { name: null, email: 'collab2@row3.com' },
        { name: null, email: 'collab3@row3.com' },
        { name: null, email: 'collab4@row3.com' }
      ]
    }
  ]
};

(async () => {
  
  await Promise.all(project.rows.map(async row => {
    
    row.owner = await serializeAndCache(row.owner);
    return Promise.all(row.collaborators.map(async collab => {
      
      let c = await serializeAndCache(collab.email);
      if (c) {
        collab.name = c.name;
        delete collab.role;
      }
      
    }));
    
  }));
  
})();

如您所见,许多promise一次都悬而未决(并且总的来说,代码完成得更快)。您的优化似乎正在起作用!我只能假设serializeAndCache背后的任何逻辑在一次被许多调用淹没时,都会表现不佳。这似乎是性能不佳的唯一解释。