我遇到了一个嵌套的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;
}
答案 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
背后的任何逻辑在一次被许多调用淹没时,都会表现不佳。这似乎是性能不佳的唯一解释。