这两个解决方案在learnyounode9 #上有什么区别?



谁能解释一下下面这两种解决方案的区别是什么?在我看来,这两种解决方案的逻辑是相同的。但第一个解决方案是正确的,第二个则不是。我知道这与数组的索引有关,但不明白它背后的逻辑。

正确的:

const http = require('http');
const bl  = require('bl');
let count = 0;
const message = [];
for (let i = 0; i < 3; i++) {
let currentIndex = i
http.get(process.argv[2+i], (res) => {
res.pipe(bl((err,data) => {
if (err) {
return console.error(err)
}
message[currentIndex] = data.toString()
count++
if(count === 3) {
for (let i = 0; i < 3; i++) {
console.log(message[i])
}
}
}))
})
}

失败:

const http = require('http');
const bl  = require('bl')
let count = 0;
const message = [];
for (let i = 0; i < 3; i++) {
http.get(process.argv[2+i], (res) => {
res.pipe(bl((err,data) => {
if (err) {
return console.error(err)
}
message[count] = data.toString()
count++
if(count === 3) {
for (let i = 0; i < 3; i++) {
console.log(message[i])
}
}
}))
})
}

关键的区别在于,第一个解决方案没有假设响应将按照发出请求的顺序返回,而第二个解决方案做出这种假设。这是一个危险的假设,所以有理由认为第一个解决方案是正确的,而第二个解决方案是错误的。

也就是说,currentIndex变量在第一个解决方案中是完全没有意义的,可以使用i(因为它在for中使用let声明)。

这里有一个稍微简化的例子来说明它们的区别:

// A utility function to stand in for the asynchronous part
function doAsyncThing(index, callback) {
// Take 800ms to respond to index === 1,
// but only 200ms for any other
setTimeout(callback, index === 1 ? 800 : 200, `response ${index}`);
}
// The first solution slightly simplified with various
// missing semicolons added
function firstSolution() {
let count = 0;
const message = [];
for (let i = 0; i < 3; i++) {
let currentIndex = i;
doAsyncThing(i, result => {
message[currentIndex] = result;
++count;
if(count === 3) {
for (let i = 0; i < 3; i++) {
console.log(message[i]);
}
}
});
}
}
// The above but using `count` instead of `currentIndex`
function secondSolution() {
let count = 0;
const message = [];
for (let i = 0; i < 3; i++) {
doAsyncThing(i, result => {
message[count] = result;
++count;
if(count === 3) {
for (let i = 0; i < 3; i++) {
console.log(message[i]);
}
}
});
}
}
console.log("First solution:");
firstSolution();
setTimeout(() => {
console.log("Second solution:");
secondSolution();
}, 1000);

第一个解决方案的输出结果依次为:

<>之前第一个解决方案:反应0反应1反应2…但第二个解决方案不是这样的:

<>之前第二个解决方案:反应0response 2 <−−−−−−−−−−−−−−−−−−−−−−无序只是为了完整,这是没有不必要的currentIndex变量的第一个解决方案(虽然我想我可能会把循环计数器的名称从i改为currentIndex或其他东西,因为在其他地方有另一个i):

// A utility function to stand in for the asynchronous part
function doAsyncThing(index, callback) {
// Take 800ms to respond to index === 1,
// but only 200ms for any other
setTimeout(callback, index === 1 ? 800 : 200, `response ${index}`);
}
// The first solution slightly simplified with various
// missing semicolons added
function firstSolution() {
let count = 0;
const message = [];
for (let i = 0; i < 3; i++) {
doAsyncThing(i, result => {
message[i] = result;
++count;
if(count === 3) {
for (let i = 0; i < 3; i++) {
console.log(message[i]);
}
}
});
}
}
firstSolution();

最新更新