为什么这个 fs.readFile 循环没有将其结果推送到我的数组?
Why is this fs.readFile loop not pushing its results to my array?
#!/usr/bin/env node
var fs = require('fs')
, async = require('async')
, program = require('commander')
program
.version('0.0.1')
.usage('<keywords>')
.parse(process.argv)
async.waterfall([
fs.readdir.bind(fs, __dirname),
parseHTML,
], saveResult)
function parseHTML(files, callback) {
var result = []
files.forEach(function(file) {
if (file.match(/\.html$/)) {
fs.readFile(file, 'utf8', function(err, data) {
if (err) throw err
result.push(data)
})
}
})
callback(null, result)
}
function saveResult(err, result) {
console.log(result)
}
我很困惑,因为 console.log(data)
确实输出了数据:
<p>File 1</p>
<p>File 2</p>
然而最后的 result
是一个空数组:[]
为什么我做错了?
您必须等到最后一个 fs.readFile()
操作完成后才能查看结果。这些是异步操作,它们会在未来的某个时间完成。在他们中的任何一个完成之前,您正在检查结果。
有很多方法可以解决这个问题,但这种方法可能对您的代码造成的更改最少,因为它只是记录已完成的数量:
function parseHTML(files, callback) {
var result = [],
cntr = 0;
files.forEach(function(file) {
if (file.match(/\.html$/)) {
fs.readFile(file, 'utf8', function(err, data) {
if (err) throw err
result.push(data)
// see if we're done processing all the results
++cntr;
if (cntr === files.length) {
callback(null, result);
}
});
} else {
++cntr;
if (cntr === files.length) {
callback(null, result);
}
}
});
}
我个人更喜欢使用 promises 和 Promise.all()
来解决这个问题。
这是一个使用 Bluebird promise 库的版本,它保留了您的一些其他结构:
var Promise = require("bluebird");
var fs = Promise.promisifyAll(require('fs'));
// your other code here
function parseHTML(files, callback) {
var promises = [];
files.forEach(function(file) {
if (file.match(/\.html$/)) {
promises.push(fs.readFileAsync(file, 'utf8'));
});
Promise.all(promises).then(function(results) {
// all results in results array
callback(null, results);
}, function(err) {
// error here
});
}
而且,这是一个完全承诺的版本:
var Promise = require("bluebird");
var fs = Promise.promisifyAll(require('fs'));
function parseHTML(files) {
var promises = [];
files.forEach(function(file) {
if (file.match(/\.html$/)) {
promises.push(fs.readFileAsync(file, 'utf8'));
});
return Promise.all(promises);
}
fs.readdirAsync(__dirname).then(parseHTML).then(function(results) {
// files are in the results array here
}).catch(function(err) {
// error here
});
#!/usr/bin/env node
var fs = require('fs')
, async = require('async')
, program = require('commander')
program
.version('0.0.1')
.usage('<keywords>')
.parse(process.argv)
async.waterfall([
fs.readdir.bind(fs, __dirname),
parseHTML,
], saveResult)
function parseHTML(files, callback) {
var result = []
files.forEach(function(file) {
if (file.match(/\.html$/)) {
fs.readFile(file, 'utf8', function(err, data) {
if (err) throw err
result.push(data)
})
}
})
callback(null, result)
}
function saveResult(err, result) {
console.log(result)
}
我很困惑,因为 console.log(data)
确实输出了数据:
<p>File 1</p>
<p>File 2</p>
然而最后的 result
是一个空数组:[]
为什么我做错了?
您必须等到最后一个 fs.readFile()
操作完成后才能查看结果。这些是异步操作,它们会在未来的某个时间完成。在他们中的任何一个完成之前,您正在检查结果。
有很多方法可以解决这个问题,但这种方法可能对您的代码造成的更改最少,因为它只是记录已完成的数量:
function parseHTML(files, callback) {
var result = [],
cntr = 0;
files.forEach(function(file) {
if (file.match(/\.html$/)) {
fs.readFile(file, 'utf8', function(err, data) {
if (err) throw err
result.push(data)
// see if we're done processing all the results
++cntr;
if (cntr === files.length) {
callback(null, result);
}
});
} else {
++cntr;
if (cntr === files.length) {
callback(null, result);
}
}
});
}
我个人更喜欢使用 promises 和 Promise.all()
来解决这个问题。
这是一个使用 Bluebird promise 库的版本,它保留了您的一些其他结构:
var Promise = require("bluebird");
var fs = Promise.promisifyAll(require('fs'));
// your other code here
function parseHTML(files, callback) {
var promises = [];
files.forEach(function(file) {
if (file.match(/\.html$/)) {
promises.push(fs.readFileAsync(file, 'utf8'));
});
Promise.all(promises).then(function(results) {
// all results in results array
callback(null, results);
}, function(err) {
// error here
});
}
而且,这是一个完全承诺的版本:
var Promise = require("bluebird");
var fs = Promise.promisifyAll(require('fs'));
function parseHTML(files) {
var promises = [];
files.forEach(function(file) {
if (file.match(/\.html$/)) {
promises.push(fs.readFileAsync(file, 'utf8'));
});
return Promise.all(promises);
}
fs.readdirAsync(__dirname).then(parseHTML).then(function(results) {
// files are in the results array here
}).catch(function(err) {
// error here
});