为什么等待导致我的流被读取
Why does an await cause my stream to be read
我有一个从文件创建的流,我打算稍后使用它。但是,我注意到如果我等待 运行 的任何异步代码,即使它与我的流完全无关,它也会导致流被读取。为什么会这样?
代码在服务器端。
const data = fs.createReadStream(filePath);
console.log(data.bytesRead); // output: 0
await new Promise(r => setTimeout(r, 2000));
console.log(data.bytesRead); // output: 65536
此解释适用于节点 v14 和之前的版本...节点 v15+ 中的行为已更改,当我在 v16 中测试时,两个 data.bytesRead
值都显示 0
。
在 fs.createReadStream()
为文件调用异步 fs.open()
之后,它会读取文件的第一个块,以便在流开始流动时可用于流式传输。这是内部预缓冲。这可能是因为它提高了性能。如果您假设 reader 将读取整个流(或其中的大部分),那么您也可以在文件打开成功后立即获取内容的第一个缓冲区,即使流不是仍然流动,或者即使调用者没有被手动调用来读取一些字节。
因为读取是异步的,结果直到您的 await
造成的延迟之后才会显示(读取在您的 await
期间完成)。所以,这就是 await
允许您看到值变化的原因。
如果您想使用 fs.createReadStream()
跟踪代码,您可以在调试器中单步执行它并准确观察它的作用。 ReadStream
构造函数中的代码结构在 v14 和最新版本之间发生了很大变化,因此如果您将在 Github 源代码中看到的内容与在调试器中逐步执行它进行比较,您可能会感到困惑如果两者不是同一个版本(这发生在我身上)。尽管在最近的版本中实现发生了变化,但想法是一样的(预取第一块内容)。
首先,它调用 ReadStream
构造函数。然后,作为其中的一部分,它打开文件并在文件打开成功后,将文件的第一个块读入其当前缓冲区。
看来这个 Github issue 似乎负责更改 readStream,使其不再自动开始读取,相应的代码更改看起来像是进入了 v15。
在 v16 ReadStream 代码 here 中,您现在可以看到文件打开的位置(在新的 _construct
方法中)并且在打开文件后,不再有任何代码可以预先-获取文件的第一个块。
我有一个从文件创建的流,我打算稍后使用它。但是,我注意到如果我等待 运行 的任何异步代码,即使它与我的流完全无关,它也会导致流被读取。为什么会这样?
代码在服务器端。
const data = fs.createReadStream(filePath);
console.log(data.bytesRead); // output: 0
await new Promise(r => setTimeout(r, 2000));
console.log(data.bytesRead); // output: 65536
此解释适用于节点 v14 和之前的版本...节点 v15+ 中的行为已更改,当我在 v16 中测试时,两个 data.bytesRead
值都显示 0
。
在 fs.createReadStream()
为文件调用异步 fs.open()
之后,它会读取文件的第一个块,以便在流开始流动时可用于流式传输。这是内部预缓冲。这可能是因为它提高了性能。如果您假设 reader 将读取整个流(或其中的大部分),那么您也可以在文件打开成功后立即获取内容的第一个缓冲区,即使流不是仍然流动,或者即使调用者没有被手动调用来读取一些字节。
因为读取是异步的,结果直到您的 await
造成的延迟之后才会显示(读取在您的 await
期间完成)。所以,这就是 await
允许您看到值变化的原因。
如果您想使用 fs.createReadStream()
跟踪代码,您可以在调试器中单步执行它并准确观察它的作用。 ReadStream
构造函数中的代码结构在 v14 和最新版本之间发生了很大变化,因此如果您将在 Github 源代码中看到的内容与在调试器中逐步执行它进行比较,您可能会感到困惑如果两者不是同一个版本(这发生在我身上)。尽管在最近的版本中实现发生了变化,但想法是一样的(预取第一块内容)。
首先,它调用 ReadStream
构造函数。然后,作为其中的一部分,它打开文件并在文件打开成功后,将文件的第一个块读入其当前缓冲区。
看来这个 Github issue 似乎负责更改 readStream,使其不再自动开始读取,相应的代码更改看起来像是进入了 v15。
在 v16 ReadStream 代码 here 中,您现在可以看到文件打开的位置(在新的 _construct
方法中)并且在打开文件后,不再有任何代码可以预先-获取文件的第一个块。