【问题标题】:Node.js writable.write return false?Node.js 可写.write 返回 false?
【发布时间】:2016-01-06 16:26:19
【问题描述】:

我想上传(流)控制写入过程。但是写入过程总是返回false。大文件上传过程停止。代码输出如下;

> Node app.js
> False
> False
> False
> False

我做错了什么?

我的代码;

app.js

var http = require('http');
var fs = require('fs');

http.createServer(function(req, res){
  var readable = fs.createReadStream('read.mkv');
  var writable  = fs.createWriteStream('write.mkv');

  readable.on('data', function(chunk){

      var buffer = writable.write(chunk);

      if(!buffer){ // ----> Always false! Why????

        readable.pause();
      }
      console.log(buffer);
  });

  writable.on('drain', function(){

    readable.resume();
  });
}).listen(8090);

【问题讨论】:

  • 你怎么知道 writable.write 总是返回 true?您在大文件中收到什么错误消息/代码?另外,你可以试试 readable.pipe(writeable) 看看同样的错误是否可重现?

标签: javascript node.js streamwriter writable


【解决方案1】:

我已修改您的程序以显示有关正在发生的事情的更多信息:

'use strict';
const fs = require('fs');

const readable = fs.createReadStream('read.mkv');
const writable  = fs.createWriteStream('write.mkv');

readable.on('data', function(chunk){
  var buffer = writable.write(chunk);

  if(!buffer){ // ----> Always false! Why????
    readable.pause();
  }
  console.log(buffer, chunk.length);
});

writable.on('drain', function(){
  readable.resume();
  console.log('drain');
});

输出:

$ node blah.js
false 65536
drain
false 65536
drain
false 65536
drain
true 8192

我还使用了不同大小的文件作为输入,所以我的输出末尾有一个true。如果我将read.mkv 的大小增加10000 字节,最后一行将显示为false 18192

发生的情况是read() 返回的每个块都足够大,导致写入流超过其默认为16384highWaterMark(假设fs.createWriteStream 返回的流)。从输出中的数字可以看出,除了最后一个之外,每个read()(错误,每个'data' 事件)都会产生65536 字节。由于将此数据量写入writable 会导致其超过其highWaterMark,因此该流建议在继续之前等待'drain'

所以,简单地说,你总是看到false 发出,因为readable 流在读取时会产生如此大的块。而且我希望不再看到任何日志表明传输已经完成。但是您确实需要注册.on('end').on('error') 才能弄清楚。

对于这样一个简单的情况,最好只使用readable.pipe(),比如:

readable.pipe(writable);

这将自动为您处理'drain'。它甚至会适当地为您调用writable.end()

请注意,pipe() 在遇到读取或写入错误时不会调用 writable.end()。如果您有一个长时间运行的进程需要对流错误具有弹性,您需要确保处理错误并关闭流以防止在您的程序运行时间足够长以达到文件描述符限制时处理泄漏。

false 是什么意思

流使程序能够通过一次处理一个块而不是将其全部加载到内存中来扩展到大量数据。在数据最终被写出之前,流可以被组织成代表数据的各种转换的管道。当write() 返回false 时,表示它已接收到足够的数据以使其忙碌一段时间。如果您继续向它发送块,它将继续接受这些块。但是,其积压的数据将增长并开始消耗更多内存。如果您忽略此返回值并继续从一个非常大的源向其发送数据,您甚至可能导致程序耗尽其地址空间并崩溃或卡住。为了使您的代码可扩展,您应该尊重false 返回并等待'drain',就像您在代码中所做的那样。

但是,false 并不意味着发生了任何不好的事情或有任何错误。事实上,在任何源流比目标流快的情况下,这种情况都会发生,并且是流 API 确保事情安全的方式。

【讨论】:

    猜你喜欢
    • 2020-08-08
    • 2011-04-09
    • 2016-02-19
    • 1970-01-01
    • 2012-09-13
    • 1970-01-01
    • 2019-01-05
    • 2018-02-17
    • 2011-12-04
    相关资源
    最近更新 更多