【发布时间】:2015-08-03 21:22:05
【问题描述】:
https://nodejs.org/api/fs.html#fs_fs_createreadstream_path_options 。 我还有一个一般性问题。
我可以假设除非文档中另有说明,否则提到的任何函数都是异步的吗?
【问题讨论】:
标签: node.js
https://nodejs.org/api/fs.html#fs_fs_createreadstream_path_options 。 我还有一个一般性问题。
我可以假设除非文档中另有说明,否则提到的任何函数都是异步的吗?
【问题讨论】:
标签: node.js
createreadstream 是异步的吗?
是和不是。这个问题实际上更多是语义问题,因为它在看起来同步的界面下隐藏了异步操作。 fs.createReadStream() 似乎有一个同步接口。它不会返回承诺或接受回调以在完成时进行通信或发回一些结果。因此,它从界面看起来是同步的。而且,我们通过使用它知道,您无需等待即可开始使用流。所以,你可以把它当作一个同步接口来使用。
这是fs.createReadStream()的签名:
fs.createReadStream(path[, options])
而且,在选项对象中,没有回调选项,也没有提及返回的承诺。这不是典型的异步接口。
另一方面,如果您查看fs.rename() 的签名:
fs.rename(oldPath, newPath, callback)
您会看到它需要一个在文档中称为“完成回调”的回调。这个函数显然是异步的。
但是,fs.createReadStream() 确实会打开一个文件,并且它会异步打开该文件而不会阻塞。
如果您想知道fs.createReadStream() 在必须异步打开文件时如何同步,那是因为fs.createReadStream() 在返回时尚未打开文件。
在流的正常使用中,您可以立即开始从流中读取。但是,在流内部,如果文件尚未打开,它将等到文件完成打开后再实际尝试从中读取。因此,打开文件的过程对流的用户是隐藏的(这通常是一件好事)。
如果您想知道文件何时真正打开,流上有一个open 事件。而且,如果打开文件时出错,则流上会出现error 事件。所以,如果你想获得技术,你可以说fs.readStream()实际上是一个异步操作,异步操作的完成是通过open或error事件来传达的。
let rstream = fs.createReadStream("temp.txt");
rstream.on('open', (fd) => {
// file opened now
});
rstream.on('error', (err) => {
// error on the stream
});
但是,在fs.createReadStream() 的正常使用中,程序员不必监视文件打开事件,因为它对用户隐藏并且在从下一个读取流时自动处理。当您创建一个读取流并立即请求从中读取(这是一个异步接口)时,流对象在内部等待文件完成打开,然后从中读取一些字节,等待文件读取完成然后通知完成读操作。因此,他们只是将文件打开完成与第一次读取结合起来,为程序员节省了一个额外的步骤,即在发出第一次读取操作之前等待文件打开完成。
所以,从技术上讲,fs.createReadStream() 是一个具有完成事件的异步操作。但是,由于它与从文件中读取相结合的方式,您通常不必像异步一样使用它,因为它的异步行为与从文件中的异步读取相结合。
【讨论】:
createReadStream中实际打开的时间是什么时候?您提到“稍后”,但什么时候完成?
fs.createReadStream() 创建了一个ReadStream 对象,该对象在构造函数中调用this.open()。但是,这是异步的,所以它会在 fs.createReadStream() 返回后的某个时间完成。流上的其他方法检查文件是否已完成打开,如果没有,它们注册一个事件处理程序以在打开完成时收到通知,并在打开完成后执行它们的工作。这可以工作,因为一切都是异步的。
open 何时结束,您可以自己在流上为open 事件注册一个事件监听器。
child_process.spawn 和 child_process.fork 采用长度为 3 的参数 stdio:[],分别对应子进程的 stdin、stdout 和 stderr。这 3 个中的任何一个的可能值都包括一个流,但如果流还不是 open(即已生成 open 事件),则会引发错误。所以在这种情况下,它不会对用户隐藏。
根据nodejs源码:
fs.createReadStream 创建一个 ReadStream 实例。
ReadStream 的 _read 方法(我们知道每个自定义可读流必须提供它的 _read 方法)调用 fs.read
我们知道 fs.read 是异步的(fs.readSync 是同步的)
【讨论】: