在不同时间分配给数组会产生不同的结果
assigning to array at different times yields different results
我有这两个不同的代码,它们略有不同但产生不同的结果:
(async () => {
const results = new Array(concurrentBrowsers).fill({});
const browsers = [];
for (let index = 0; index < concurrentBrowsers; index++) {
browsers.push(
(async function() {
let i = index;
const browser = await puppeteer.launch({ headless });
const page = await getNewPage({ browser });
results[i].loginPage = await timer(actions.loginPage, { page }); // <---- this line
results[i].homePage = await timer(actions.homePage, {
page,
username,
password
});
console.log(i, results[i]);
browser.close();
})()
);
}
await Promise.all(browsers);
})();
结果是
1 { loginPage: 2.924, homePage: 19.939 }
2 { loginPage: 2.924, homePage: 21.388 }
3 { loginPage: 2.924, homePage: 21.122 }
0 { loginPage: 2.924, homePage: 21.305 }
4 { loginPage: 2.924, homePage: 21.6 }
还有一个:
(async () => {
const results = new Array(concurrentBrowsers).fill({});
const browsers = [];
for (let index = 0; index < concurrentBrowsers; index++) {
browsers.push(
(async function() {
let i = index;
const browser = await puppeteer.launch({ headless });
const page = await getNewPage({ browser });
let loginPageTime = await timer(actions.loginPage, { page }); // <---- this line
let homePageTime = await timer(actions.homePage, {
page,
username,
password
});
results[i].loginPage = loginPageTime;
results[i].homePage = homePageTime;
console.log(i, results[i]);
browser.close();
})()
);
}
await Promise.all(browsers);
})();
结果是
2 { loginPage: 3.291, homePage: 17.911 }
4 { loginPage: 3.226, homePage: 18.949 }
1 { loginPage: 3.047, homePage: 22.619 }
0 { loginPage: 3.291, homePage: 24.508 }
3 { loginPage: 3.059, homePage: 26.391 }
第一个代码有一个错误,似乎 loginPage
结果总是取自最后一次迭代,正如您所看到的,在所有迭代中都设置为相同的值。
唯一的区别是我在第一个例子中将计时器的结果分配给results[i].loginPage
,在第二个例子中分配给loginPageTime
。
有人可以解释一下这个区别吗?
谢谢
事实上,两种代码变体都有相同的问题,但第二个代码块没有显示出问题所在:
const results = new Array(concurrentBrowsers).fill({});
这会创建 one(!) 空对象并将其分配给 all 数组条目。您对该对象所做的任何更改都将通过所有数组条目看到,因为它们都引用同一个对象。
您在第一个版本中看到不一致的原因是,在同一迭代中的两个 await
表达式之间发生了其他赋值,而第二个代码版本没有直到 console.log
.
之前的赋值
您可以执行 results
的正确初始化,如下所示:
const results = Array.from(new Array(concurrentBrowsers), _ => ({}));
我有这两个不同的代码,它们略有不同但产生不同的结果:
(async () => {
const results = new Array(concurrentBrowsers).fill({});
const browsers = [];
for (let index = 0; index < concurrentBrowsers; index++) {
browsers.push(
(async function() {
let i = index;
const browser = await puppeteer.launch({ headless });
const page = await getNewPage({ browser });
results[i].loginPage = await timer(actions.loginPage, { page }); // <---- this line
results[i].homePage = await timer(actions.homePage, {
page,
username,
password
});
console.log(i, results[i]);
browser.close();
})()
);
}
await Promise.all(browsers);
})();
结果是
1 { loginPage: 2.924, homePage: 19.939 }
2 { loginPage: 2.924, homePage: 21.388 }
3 { loginPage: 2.924, homePage: 21.122 }
0 { loginPage: 2.924, homePage: 21.305 }
4 { loginPage: 2.924, homePage: 21.6 }
还有一个:
(async () => {
const results = new Array(concurrentBrowsers).fill({});
const browsers = [];
for (let index = 0; index < concurrentBrowsers; index++) {
browsers.push(
(async function() {
let i = index;
const browser = await puppeteer.launch({ headless });
const page = await getNewPage({ browser });
let loginPageTime = await timer(actions.loginPage, { page }); // <---- this line
let homePageTime = await timer(actions.homePage, {
page,
username,
password
});
results[i].loginPage = loginPageTime;
results[i].homePage = homePageTime;
console.log(i, results[i]);
browser.close();
})()
);
}
await Promise.all(browsers);
})();
结果是
2 { loginPage: 3.291, homePage: 17.911 }
4 { loginPage: 3.226, homePage: 18.949 }
1 { loginPage: 3.047, homePage: 22.619 }
0 { loginPage: 3.291, homePage: 24.508 }
3 { loginPage: 3.059, homePage: 26.391 }
第一个代码有一个错误,似乎 loginPage
结果总是取自最后一次迭代,正如您所看到的,在所有迭代中都设置为相同的值。
唯一的区别是我在第一个例子中将计时器的结果分配给results[i].loginPage
,在第二个例子中分配给loginPageTime
。
有人可以解释一下这个区别吗?
谢谢
事实上,两种代码变体都有相同的问题,但第二个代码块没有显示出问题所在:
const results = new Array(concurrentBrowsers).fill({});
这会创建 one(!) 空对象并将其分配给 all 数组条目。您对该对象所做的任何更改都将通过所有数组条目看到,因为它们都引用同一个对象。
您在第一个版本中看到不一致的原因是,在同一迭代中的两个 await
表达式之间发生了其他赋值,而第二个代码版本没有直到 console.log
.
您可以执行 results
的正确初始化,如下所示:
const results = Array.from(new Array(concurrentBrowsers), _ => ({}));