我想将多个文件一个接一个地流式传输到浏览器。举例来说,请考虑将多个 CSS 文件串联在一起交付。
我正在使用的代码是:
var directory = path.join(__dirname, 'css');
fs.readdir(directory, function (err, files) {
async.eachSeries(files, function (file, callback) {
if (!endsWith(file, '.css')) { return callback(); } // (1)
var currentFile = path.join(directory, file);
fs.stat(currentFile, function (err, stats) {
if (stats.isDirectory()) { return callback(); } // (2)
var stream = fs.createReadStream(currentFile).on('end', function () {
callback(); // (3)
});
stream.pipe(res, { end: false }); // (4)
});
}, function () {
res.end(); // (5)
});
});
这个想法是我
- 过滤掉所有没有文件扩展名的文件
.css
。 - 过滤掉所有目录。
- 完全读取文件后继续下一个文件。
- 将每个文件通过管道传输到响应流而不关闭它。
- 一旦所有文件都通过管道传输,就结束响应流。
问题是只有第一个.css
文件被管道传输,并且所有剩余的文件都丢失了。就好像(3)会在第一个(4)之后直接跳转到(5)。
有趣的是,如果我将第 (4) 行替换为
stream.on('data', function (data) {
console.log(data.toString('utf8'));
});
一切都按预期工作:我看到多个文件。如果我然后将此代码更改为
stream.on('data', function (data) {
res.write(data.toString('utf8'));
});
所有文件都希望第一个再次丢失。
我究竟做错了什么?
PS:错误发生在使用 Node.js 0.8.7 以及使用 0.8.22 时。
更新
好的,如果您将代码更改如下:
var directory = path.join(__dirname, 'css');
fs.readdir(directory, function (err, files) {
var concatenated = '';
async.eachSeries(files, function (file, callback) {
if (!endsWith(file, '.css')) { return callback(); }
var currentFile = path.join(directory, file);
fs.stat(currentFile, function (err, stats) {
if (stats.isDirectory()) { return callback(); }
var stream = fs.createReadStream(currentFile).on('end', function () {
callback();
}).on('data', function (data) { concatenated += data.toString('utf8'); });
});
}, function () {
res.write(concatenated);
res.end();
});
});
但为什么?为什么我不能res.write
多次调用而不是先总结所有块,然后一次将它们全部写入?