为什么Node JS阻止异步文件操作?

时间:2014-08-17 04:07:04

标签: node.js asynchronous

我的印象是,虽然Node JS是单线程的,但文件io是异步的。

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

var server = app.listen(1337, function() {
    console.log('Listening on port %d', server.address().port);
});

app.get('/home', function(req, res){
  console.log("/home")

  res.sendFile('C:\\Users\\Owner\\AppData\\Roaming\\npm\\test.html');
  //var file = fs.createReadStream('C:/Users/Owner/AppData/Roaming/npm/test.html');
  //file.on("open", function(){
  //   file.pipe(res);
  //});
});

app.get('/home2', function(req, res){
  console.log("/home2")

  res.sendFile('C:\\Users\\Owner\\AppData\\Roaming\\npm\\test2.html');
  //var file = fs.createReadStream('C:/Users/Owner/AppData/Roaming/npm/test.html');
  //file.on("open", function(){
  //   file.pipe(res);
  //});
});

app.get('/music', function(req, res){
  console.log("/music")
  //res.sendFile('C:\\Users\\Owner\\AppData\\Roaming\\npm\\01 Give Life Back To Music.mp4');
  var readStream = fs.createReadStream('C:\\Users\\Owner\\AppData\\Roaming\\npm\\01 Give Life Back To Music.mp4');
  console.log("/afterRead");
  readStream.on('data', function(data) {
        var flushed = res.write(data);
        // Pause the read stream when the write stream gets saturated
        console.log( 'streaming data' );
        if(!flushed){
            readStream.pause();
        }
    });

    res.on('drain', function() {
        // Resume the read stream when the write stream gets hungry 
        readStream.resume();
    });

  readStream.on('end', function () {
    res.end();
    console.log('end');
  });
});

app.get('/music2', function(req, res){
  console.log("/music2")
  //res.sendFile('C:\\Users\\Owner\\AppData\\Roaming\\npm\\01 Give Life Back To Music.mp4');
  var readStream = fs.createReadStream('C:\\Users\\Owner\\AppData\\Roaming\\npm\\01 Give Life Back To Music.mp4');
  console.log("/afterRead");
  readStream.on('data', function(data) {
        var flushed = res.write(data);
        // Pause the read stream when the write stream gets saturated
        console.log( 'streaming data' );
        if(!flushed){
            readStream.pause();
        }
    });

    res.on('drain', function() {
        // Resume the read stream when the write stream gets hungry 
        readStream.resume();
    });

  readStream.on('end', function () {
    res.end();
    console.log('end');
  });
});

上面是服务器代码,这是我的HTML:

<html>
    <script>

    </script>
    <body>
        <video width="320" height="240" controls>
          <source src="http://localhost:1337/music1" type="video/mp4">
          Your browser does not support the video tag.
        </video>
    </body>
    </html>

<html>
<script>

</script>
<body>
    <video width="320" height="240" controls>
      <source src="http://localhost:1337/music2" type="video/mp4">
      Your browser does not support the video tag.
    </video>
</body>
</html>

我希望能够不止一次调用localhost:1337 / music,但是当我在Google Chrome(或Firefox或Internet Explorer 11)的两个标签中调用localhost:1337 / home时页面不会加载音频,直到所有字节都已传输给localhost:1337 / music的第一个请求。代码是异步的,我知道它不会阻塞,因为如果阻塞,第二个请求... / home2不应该提供文件。

有人知道异步代码阻塞的原因吗?我通过Chrome中的开发人员工具验证了正在调用/ music和/ music2(从浏览器的角度来看)。我也遇到了不使用Express的同样问题,所以我确信它不是框架。

  • 另外,我有控制台记录。当第二页加载时,我在控制台中看到第二个/ home以及几个&#34;流数据&#34;因为它是第一页的流数据。 Chrome说/音乐请求已经消失,但是控制台没有打印任何暗示该功能甚至没有被执行的东西 - 暗示其他东西阻止了它。

3 个答案:

答案 0 :(得分:2)

Chrome一次只下载一个文件的副本(例如,如果您下载了一个非常大的文件,对该文件的后续请求就会排队,甚至跨标签)。开发环境表示请求正在等待处理,但是挂起的实际上是Chrome的限制,而不是Node JS服务器的限制。文件下载专门与URL作为密钥绑定,这就是为什么我能够让不同的URL下载相同的文件,以及为什么我可以在下载此文件时向服务器发出其他请求。

答案 1 :(得分:-1)

您可能遇到了浏览器的连接限制。尝试增加限制(如果可以的话,我认为你至少可以在Firefox中这样做)并再试一次。

此外,您只需将文件传输到响应,而不是手动收听数据&#39;并且&#39;结束&#39;。例如:

app.get('/music2', function(req, res){
  console.log("/music2")
  //res.sendFile('C:\\Users\\Owner\\AppData\\Roaming\\npm\\01 Give Life Back To Music.mp4');
  var readStream = fs.createReadStream('C:\\Users\\Owner\\AppData\\Roaming\\npm\\01 Give Life Back To Music.mp4');
  console.log("/afterRead");
  readStream.pipe(res);
});

答案 2 :(得分:-1)

似乎createReadStream是阻止文件。我试过这段代码

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

http.createServer(function (req, res) {
    var str = req.url.split('?')[1];
    var query = qs.parse(str);

    var readStream = fs.createReadStream('./response' + (query.q || '') + '.json');
    readStream.on('data', function(data) {
        var flushed = res.write(data);
        console.log( 'streaming data' );
        if(!flushed){
            readStream.pause();
        }
    });

    res.on('drain', function() {
        readStream.resume();
    });
}).listen(1337, '127.0.0.1');

并打开了两个带有localhostlocalhost/?q=1的标签,它可以很好地读取两个单独的文件,但如果您尝试通过两个进程读取一个文件,则第二个请求会挂起。