【问题标题】:Is createreadstream asynchronous?createreadstream 是异步的吗?
【发布时间】:2015-08-03 21:22:05
【问题描述】:

https://nodejs.org/api/fs.html#fs_fs_createreadstream_path_options 。 我还有一个一般性问题。

我可以假设除非文档中另有说明,否则提到的任何函数都是异步的吗?

【问题讨论】:

    标签: node.js


    【解决方案1】:

    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()实际上是一个异步操作,异步操作的完成是通过openerror事件来传达的。

    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中实际打开的时间是什么时候?您提到“稍后”,但什么时候完成?
    • @jmq - 如果您查看the source code,您可以看到fs.createReadStream() 创建了一个ReadStream 对象,该对象在构造函数中调用this.open()。但是,这是异步的,所以它会在 fs.createReadStream() 返回后的某个时间完成。流上的其他方法检查文件是否已完成打开,如果没有,它们注册一个事件处理程序以在打开完成时收到通知,并在打开完成后执行它们的工作。这可以工作,因为一切都是异步的。
    • @jmq - 如果您想知道open 何时结束,您可以自己在流上为open 事件注册一个事件监听器。
    • 重写了这个答案,使其在技术上更加准确,并详细说明它在幕后的实际工作方式。
    • child_process.spawnchild_process.fork 采用长度为 3 的参数 stdio:[],分别对应子进程的 stdin、stdout 和 stderr。这 3 个中的任何一个的可能值都包括一个流,但如果流还不是 open(即已生成 open 事件),则会引发错误。所以在这种情况下,它不会对用户隐藏。
    【解决方案2】:

    根据nodejs源码:

    1. fs.createReadStream 创建一个 ReadStream 实例。

    2. ReadStream 的 _read 方法(我们知道每个自定义可读流必须提供它的 _read 方法)调用 fs.read

    3. 我们知道 fs.read 是异步的(fs.readSync 是同步的)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-27
      • 2017-02-19
      • 2019-01-05
      • 2021-03-30
      相关资源
      最近更新 更多