http.ServerResponse.write()阻塞了吗?

时间:2013-02-11 18:16:37

标签: node.js asynchronous blocking httpserver

是否可以编写非阻塞response.write?我写了一个简单的测试,看看其他客户端是否可以在下载文件时连接:

var connect = require('connect');

var longString = 'a';
for (var i = 0; i < 29; i++) { // 512 MiB
   longString += longString;
}
console.log(longString.length)

function download(request, response) {
    response.setHeader("Content-Length", longString.length);
    response.setHeader("Content-Type", "application/force-download");
    response.setHeader("Content-Disposition", 'attachment; filename="file"');
    response.write(longString);
    response.end();
}

var app = connect().use(download);
connect.createServer(app).listen(80);

似乎write正在阻止!

我做错了吗?

更新因此,它不会阻止并且它会在同一时间阻止。在两个文件可以同时下载的意义上它不会阻塞。并且它在某种意义上阻止了创建缓冲区是一个很长的操作。

2 个答案:

答案 0 :(得分:2)

任何严格按JavaScript完成的处理都会阻止。 response.write(),至少从v0.8开始,no exceptionstream

  

第一次调用response.write()时,它会将缓冲的头信息和第一个主体发送到客户端。第二次调用response.write()时,Node假定您将要传输数据,并单独发送。也就是说,响应被缓冲到第一个身体块。

     

如果将整个数据成功刷新到内核缓冲区,则返回true。如果全部或部分数据在用户内存中排队,则返回false。当缓冲区再次释放时,将发出'drain'

可以节省一些时间是在尝试longString之前将Buffer转换为write(),因为无论如何转换都会发生:

var longString = 'a';
for (...) { ... }
longString = new Buffer(longString);

但是,对longString var longString = 'a', chunkCount = Math.pow(2, 29), bufferSize = Buffer.byteLength(longString), longBuffer = new Buffer(longString); function download(request, response) { var current = 0; response.setHeader("Content-Length", bufferSize * chunkCount); response.setHeader("Content-Type", "application/force-download"); response.setHeader("Content-Disposition", 'attachment; filename="file"'); function writeChunk() { if (current < chunkCount) { current++; if (response.write(longBuffer)) { process.nextTick(writeChunk); } else { response.once('drain', writeChunk); } } else { response.end(); } } writeChunk(); } 的各个块而不是一次性({注释:Streams are changing in v0.10)可能会更好{<3}}:

function download(request, response) {
    // response.setHeader(...)
    // ...

    fs.createReadStream('./file-on-disk').pipe(response);
}

而且,如果最终目标是从磁盘流式传输文件,fs.createReadStream()stream.pipe()可以更轻松地实现这一目标:

{{1}}

答案 1 :(得分:1)

不,它没有阻止,我尝试了一个来自IE和其他来自Firefox。我先做IE,但仍然可以先从firefox下载文件。 我尝试了1 MB(i&lt; 20)它的工作速度相同。 你应该知道你创建的longString需要内存分配。尝试为我做&< 30(在Windows 7上)它将抛出致命错误:JS分配失败 - 处理内存不足。

内存分配/复制需要时间。由于它是一个巨大的文件,响应是耗时的,你的下载看起来像阻止。自己尝试使用较小的值(i <20或其他)