是http.ServerResponse.write()阻塞?
有没有可能写非阻塞response.write? 我已经写了一个简单的testing,看看其他客户端可以连接,而一个下载文件:
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
封锁!
难道我做错了什么?
更新所以,它不会阻塞,并在同一时间阻止。 这并不意味着可以同时下载两个文件。 而且它阻止了创build缓冲区是一个漫长的操作。
任何严格的JavaScript处理都将被阻止。 response.write()
,至less从v0.8开始, 也不例外 :
第一次调用
response.write()
,它会将caching的头信息和第一个正文发送给客户端。 第二次调用response.write()
,Node假定你要传输数据,并分别发送。 也就是说,响应被缓冲到第一个主体。如果整个数据已成功刷新到内核缓冲区,则返回
true
。 如果全部或部分数据在用户存储器中排队,则返回false
。 当缓冲区再次空闲时,将会发出'drain'
。
什么可以节省一些时间是在尝试write()
之前将longString
转换为Buffer
,因为无论如何都会发生转换:
var longString = 'a'; for (...) { ... } longString = new Buffer(longString);
但是,可能会更好地将longString
的各个部分进行stream式处理,而不是一次全部处理(注意: stream在v0.10中正在改变 ):
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(); }
而且,如果最终目标是从磁盘stream式传输文件,使用fs.createReadStream()
和stream.pipe()
可以更容易:
function download(request, response) { // response.setHeader(...) // ... fs.createReadStream('./file-on-disk').pipe(response); }
不,它不阻止,我尝试了一个从IE和Firefox等。 我做了第一个IE,但仍然可以从Firefox下载文件。 我尝试了1 MB(我<20),它只是更快地工作。 你应该知道,无论你创build什么longString都需要内存分配。 尝试做我为<30(在Windows 7),它会抛出致命错误:JS分配失败 – 进程内存不足。
内存分配/复制需要时间。 由于它是一个巨大的文件,反应是时间和你的下载看起来像阻塞。 自己尝试一下较小的值(我<20或某物)