Давайте рассмотрим использование тайм-аутов для имитации ваших асинхронных вызовов.
Этот код эквивалентен вашему первому примеру до того, как вы сделали оптимизацию. Обратите внимание, что в любой момент времени ожидает только одно обещание:
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
, ведет себя плохо, когда он переполняется множеством вызовов одновременно. Кажется, это единственное объяснение низкой производительности.