在node.js应用程序中使用q.all的q.js实现并行异步性

时间:2014-03-05 01:15:32

标签: node.js q

背景介绍:我编写了下面的代码来指示node.js:(1)从三个文本文件中组装一个HTML页面,其中我分别存储了pageheader,pagebody和pagefooter组件。显然,这些页面片段必须按正确的顺序组装。另一方面,完全没有要求必须在组装之前以任何顺序从文本文件中提取这些页面片段。我希望通过实现并行异步性来利用它。

实施代码:

var sys = require('sys'),
http = require('http'),
fs = require('fs'),
Q = require('q'),
fullpage, pageheader, pagebody, pagefooter;

fullpage = '';

fs_readheader = fs.readFile('./htmlfiles.1', 'utf-8', function (err, data) {
   if (err) { throw err; }
   return pageheader = data;
});

fs_readbody = fs.readFile('./htmlfiles.2', 'utf-8', function (err, data) {
  if (err) { throw err; }
  return pagebody = data;
});

fs_readfooter = fs.readFile('./htmlfiles.3', 'utf-8', function (err, data) {
  if (err) { throw err; }
  return pagefooter = data;
});

finish = function(err, data) {
  if (err) { throw err; }
  console.log(pageheader);
  data = pageheader + pagebody + pagefooter;
  console.log(data);
  return fullpage = data;
}();


Q.all([fs_readheader,fs_readbody,fs_readfooter]).then(finish);


http.createServer(function(request, response) {
  response.writeHeader(200, {"Content-Type": "text/html"});
  response.write(fullpage);
  response.end();
}).listen(8001);

问题:node.js服务器在127.0.0.1:8001处没有显示任何内容我当然希望完整呈现HTML页面。我使用的是q.js版本1.00,这是q.js的最新版本。

后果: 为了回应Barry-Johnson的全面意见,我将Barry-Johnson的代码修改为以下形式:

var http = require('http'),
  fs = require('fs'),
  Q = require('q');

var readFileP = Q.denodeify(fs.readFile);

http.createServer(function(request, response) {
  Q.all([ readFileP('./htmlfiles.1', 'utf-8'),
          readFileP('./htmlfiles.2', 'utf-8'),
          readFileP('./htmlfiles.3', 'utf-8') ])
    .done(function(content){
        response.writeHead(200, {"Content-Type": "text/html"});
        response.end(content.join(''));
    }); 

}).listen(8001);

结果正是我想要的,一个完全组装的HTML页面 - 按照正确的顺序。我将''作为参数添加到“join”方法,因为我不希望这些部分用逗号连接。我使用了“完成”方法,因为我希望任何未捕获的错误都可以浮动。我理解,一般来说,我们不希望任何生产代码崩溃,Barry-Johnson实施“失败”方法就可以达到这个目的。

1 个答案:

答案 0 :(得分:8)

SLaks在承诺方面是正确的。更一般地说,你要么有一个糟糕的复制/粘贴,要么承诺问题是你所经历的其他许多问题。让你的承诺在上面的代码中工作不会单独得到我相信你正在寻找的结果。

然而,只关注承诺 - 您需要查看Q.denodeifyQ.ninvokeQ.nfapply等。请参阅Q文档的Adapting Node section。这些调用允许您使用遵循标准节点约定的函数,这些函数具有尾随回调,而是将它们作为承诺返回函数进行操作。

这是个好消息 - 您需要处理的代码少得多。有一些评论的版本留下了一些原始的冗长:

var sys = require('sys'),
    http = require('http'),
    fs = require('fs'),
    Q = require('q'),
    fullpage, pageheader, pagebody, pagefooter;

var readFileP = Q.denodeify(fs.readFile);

var fsReadheader = readFileP('./file1.html', 'utf-8');
var fsReadBody = readFileP('./file2.html', 'utf-8');
var fsReadFooter = readFileP('./file3.html', 'utf-8');

//  This is where you had Q.all before - which is probably not what you want,
// or did you want to just build the page once and have it static for the life
// of the app? If that is the case, promises are kind of pointless and you may
// as well K.I.S.S. and just read the bits synchronously at startup

http.createServer(function(request, response) {
    // you should probably wait to write out the response until you know if you have success.
    // but again, maybe you do want this to be totally static content
    response.writeHead(200, {"Content-Type": "text/html"});
    // I am assuming you wanted to load the files at request time, possibly
    // in preparation to adapting your code to make ti more dynamic.
    Q.all([fsReadheader,fsReadBody,fsReadFooter])
        .then(function (x) {
            // this was your old 'finish' function - doesn't really do much.
            // I used join instead of concatenating. less typing. And no typing
            // if you ever add file4
            return x.join();})
        .then(function(content){
            // You could response.write() as well, but you can send data with .end()
            response.end(content);
        })
        .fail(function(e){
            // here is where your error handler goes. any error will end up here.'
            // you could have more granular erro handling
            response.writeHead(500, 'Bad news, Tex');
            response.end('No dice');
        });
    //
}).listen(8001);

然而,除非我通过按键获得报酬,否则我会这样写:

var http = require('http'),
    fs = require('fs'),
    Q = require('q');

var readFileP = Q.denodeify(fs.readFile);

http.createServer(function(request, response) {
    Q.all([ readFileP('./file1.html', 'utf-8'),
            readFileP('./file2.html', 'utf-8'),
            readFileP('./file3.html', 'utf-8') ])
        .then(function(content){
            response.writeHead(200, {"Content-Type": "text/html"});
            response.end(content.join());
        })
        .fail(function(e){
            response.writeHead(500, 'Bad news, Tex');
            response.end('No dice');
        });
    //
}).listen(8001);