Node.js本质上是异步和事件驱动的,因此非常擅长处理I/O密集型任务。如果您的应用程序需要执行I/O操作,可以利用Node.js提供的流(Streams)功能。
pipe()
函数是Node.js流中的有用工具,允许从源读取数据并写入目标,而无需手动管理数据流stream.pipeline()
和stream.finished()
等实用程序以及基于Promise的API,以实现更好的错误处理和流控制Node.js中的流受到Unix管道的启发,提供了一种以流式方式从源读取数据并将其传输到目标的机制。简单地说,流就是一个EventEmitter,并实现了一些特殊方法。根据实现的方法,流可以是可读、可写、双工或转换。
可读流允许您从源读取数据。源可以是任何东西:文件系统中的简单文件、内存中的缓冲区,甚至是另一个流。
从流中读取数据的最佳方法是监听data事件并附加回调:
const fs = require('fs');
const readableStream = fs.createReadStream('file.txt');
let data = '';
readableStream.on('data', function(chunk) {
data += chunk;
});
readableStream.on('end', function() {
console.log(data);
});
readableStream.on('error', (err) => {
console.error('Error reading stream:', err);
});
我们可以使用async/await重写上面的代码:
const fs = require('fs');
const { Readable } = require('stream');
const { promisify } = require('util');
const streamToString = async (stream) => {
const chunks = [];
for await (const chunk of stream) {
chunks.push(typeof chunk === 'string' ? chunk : chunk.toString());
}
return chunks.join('');
};
async function readFile() {
try {
const readableStream = fs.createReadStream('file.txt');
const content = await streamToString(readableStream);
console.log(content);
} catch (err) {
console.error('Error reading file:', err);
}
}
readFile();
可写流允许您将数据写入目标。与可读流一样,它们也是EventEmitter,并在不同点发出各种事件。
要将数据写入可写流,您需要在流实例上调用write():
const fs = require('fs');
const readableStream = fs.createReadStream('file1.txt');
const writableStream = fs.createWriteStream('file2.txt');
readableStream.setEncoding('utf8');
readableStream.on('data', function(chunk) {
writableStream.write(chunk);
});
更好的方法是处理背压:
const fs = require('fs');
const readableStream = fs.createReadStream('file1.txt');
const writableStream = fs.createWriteStream('file2.txt');
readableStream.setEncoding('utf8');
readableStream.on('data', function(chunk) {
const canContinue = writableStream.write(chunk);
if (!canContinue) {
readableStream.pause();
}
});
writableStream.on('drain', function() {
readableStream.resume();
});
readableStream.on('end', function() {
writableStream.end();
});
readableStream.on('error', (err) => {
console.error('Read error:', err);
writableStream.end();
});
writableStream.on('error', (err) => {
console.error('Write error:', err);
});
双工流是可读和可写流的组合。它们维护两个独立的内部缓冲区,一个用于读取,一个用于写入,彼此独立运行。
转换流是一种特殊的双工流,可以在数据写入和读取时修改或转换数据。与双工流不同,双工流的输入和输出是分开的,而转换流的输出与其输入直接相关。
const { Transform } = require('stream');
const upperCaseTr = new Transform({
transform(chunk, encoding, callback) {
this.push(chunk.toString().toUpperCase());
callback();
}
});
process.stdin
.pipe(upperCaseTr)
.pipe(process.stdout);
这就是流的基础知识。流、管道和链是Node.js中最核心和最强大的功能。如果使用得当,流确实可以帮助您编写简洁且高性能的代码来执行I/O操作。只需确保正确处理流错误并适当关闭流以防止内存泄漏。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。