Вложенная карта Promise.all async / await - PullRequest
0 голосов
/ 16 июня 2020

Я обнаружил вложенный для l oop с операциями ожидания внутри них, как показано ниже:

    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. для повышения производительности я хочу использовать обещание.all, как показано ниже, но иногда время выполнения примерно такое же, а иногда обещание.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 Ответ

1 голос
/ 16 июня 2020

Давайте рассмотрим использование тайм-аутов для имитации ваших асинхронных вызовов.

Этот код эквивалентен вашему первому примеру до того, как вы сделали оптимизацию. Обратите внимание, что в любой момент времени ожидает только одно обещание:

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

Как видите, многие обещания ожидают выполнения сразу (и в целом код завершается быстрее). Кажется, ваша оптимизация работает! Я могу только предположить, что любой лог c, лежащий за serializeAndCache, ведет себя плохо, когда он переполняется множеством вызовов одновременно. Кажется, это единственное объяснение низкой производительности.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...