老生常谈,异步 + 循环【已结束】
发布于 5 年前 作者 CRAZYFAKE 3853 次浏览 来自 问答
var fs = require('fs');
var files = ['./files/a', './files/b', './files/c'];

for (var i = 0; i < files.length; i++) {
    fs.readFile(files[i], 'utf-8', function(err, contents) {
        console.log(files[i] + ': ' + contents);
    });
}
// undefined: aaaaaaaa
// undefined: bbbbbbbb
// undefined: cccccccc


for (let i = 0; i < files.length; i++) {
    fs.readFile(files[i], 'utf-8', function(err, contents) {
        console.log(files[i] + ': ' + contents);
    });
}
// ./files/a: aaaaaaaa
// ./files/b: bbbbbbbb
// ./files/c: cccccccc


files.forEach(function(element, i) {
    fs.readFile(element, 'utf-8', function(err, contents) {
        console.log(files[i] + ': ' + contents);
    });
});
// ./files/a: aaaaaaaa
// ./files/b: bbbbbbbb
// ./files/c: cccccccc
8 回复

我建议文件的大小不同

来自酷炫的 CNodeMD

我想知道为啥会这样?是跟es6块级作用域有关吗? From Noder

第一个循环里因为var的原因i的值变为了3,所以输出的文件名是file[3]===undefined 为什么依然能获得相应文件的内容?因为给readFile传的参是按照for循环里正常的012,在readFile回调的时候i才变为3 和下面这个是一个意思

for (var i = 0; i < 3; i++) {
    setTimeout((u)=>{
		console.log(`${u}:${i}`);
	},0,i);
}
// 0:3
// 1:3
// 2:3

再详细一点 i=0 readfile 0 开始 i=1 readfile 1 开始 i=2 readfile 2 开始 i=3 for循环结束 readfile依次完成,注意此时的i已经变为3(如果三个文件大小不同的话下面三个顺序也可能会打乱): readfile 0 读取获得 aaaaaaaa 回调 console.log file[3]:aaaaaaaa readfile 1 读取获得 bbbbbbbb 回调 console.log file[3]:bbbbbbbb readfile 2 读取获得 cccccccc 回调 console.log file[3]:cccccccc

@dislido 再给解释下let,虽然我也看了书但是感觉你解释的更容易理解 From Noder

@lei2231 var的问题在于它会变量提升,对变量的声明会提升到作用域顶部

for (var i = 0; i < files.length; i++) {
    fs.readFile(files[i], 'utf-8', function(err, contents) {
        console.log(files[i] + ': ' + contents);
    });
}

实际上是

var i; // 把这个var改成let也不会有区别
for (i = 0; i < files.length; i++) {
    fs.readFile(files[i], 'utf-8', function(err, contents) {
        console.log(files[i] + ': ' + contents);
    });
}

所以在回调函数那里拿到的i其实是在for外面定义的那个i(已经经过for循环变成了3)

而let不会变量提升,i只存在于for内部,它的表现和我们看到的一样,回调函数拿到的是调用readfile时的i的值 简单的说,并不是let有什么特别的功能,而是var有麻烦的特性而已

其实问题的关键就在于,第一个for循环的var i使 i 泄漏成了全局变量。所以在回调结束之后,i变成了3

回到顶部