The background briefing: I have written the code below to instruct node.js to: (1) assemble an HTML page from three text files in which I stored the pageheader, pagebody and pagefooter components, respectively. Obviously, these page fragments must be assembled in the proper order. On the other hand, there is no requirement at all that these page fragments must be extracted from their text files in any order prior to their being assembled. And I want to take advantage of that by implementing parallel asynchronicity.
The implementation code:
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);
The Issue: the node.js server is not displaying anything at 127.0.0.1:8001 I expected, of course, a full rendering of the HTML page. I am using version 1.00 of q.js, which is the latest version of q.js at this point in time.
Aftermath: In response to Barry-Johnson's comprehensive input, I have modified Barry-Johnson's code to this form:
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);
The result is exactly what I want, a fully assembled HTML page - in the correct order. I added '' as a parameter to the "join" method because I don't want the pieces to be joined by a comma. I used the "done" method because I wanted any uncaught error to float up. I understand that, in general, we don't want any production code to crash and Barry-Johnson's implementation of the "fail" method is fine for that purpose.
SLaks is correct regarding promises. And more generally, you either had a bad copy/paste or the promises issue is sort of secondary to so much else you have going on. Getting your promises working in the above code would not alone get the result I believe you are seeking.
However focusing on the promises - you need to look at Q.denodeify
, Q.ninvoke
, Q.nfapply
etc. See the Adapting Node section of the Q doc. These are calls that let you work with functions which follow the standard node convention of having a trailing callback and instead manipulate them as promise-returning functions.
Here's the good news - you've got a lot less code you need to deal with. A version with some comments the leaves in some of the original verbosity:
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);
However, unless I was getting paid by the keystroke, I would write it like this:
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);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With