I'm writing a simple request handler to return a pair of css files. Using fs.readFileSync this was easy. However, I'm having difficulty accomplishing the same task using the async version of readFile. Below is my code. Having my response.write() method calls split among two different callbacks seems to be problematic. Can someone point out what I've done wrong? Interestingly this code works if I put response.end() inside of the first else statement. However, that creates a problem in that the second css file does not get returned (because response.end() has already been fired).
function css(response) { response.writeHead(200, {"Content-Type": "text/css"}); fs.readFile('css/bootstrap.css', function(error, content){ if(error){ console.log(error); } else{ response.write(content); } }); fs.readFile('css/bootstrap-responsive.css', function(error, content){ if(error){ console.log(error); } else{ response.write(content) } }); response.end(); }
One solution you pinned it by saying "package". Put the files in a archive and send one file res. write(archive_content). Of course change the content-type accordingly.
readFile. Returns the contents of the file named filename. If encoding is specified then this function returns a string. Otherwise it returns a buffer.
readFile() method is used to read the file. This method read the entire file into buffer. To load the fs module, we use require() method. It Asynchronously reads the entire contents of a file. Syntax: fsPromises.readFile( path, options )
The primary issue with what you have is that response.end()
gets called right away. You need to only call it after the files have done their response.write
calls.
The easiest way would be to use a control flow library. Managing multiple asynchronous callbacks is generally complicated.
https://github.com/joyent/node/wiki/modules#wiki-async-flow
I'm going to use the async library because it's the one I know best.
var fs = require('fs'); var async = require('async'); function css(response) { response.writeHead(200, {"Content-Type": "text/css"}); async.eachSeries( // Pass items to iterate over ['css/bootstrap.css', 'css/bootstrap-responsive.css'], // Pass iterator function that is called for each item function(filename, cb) { fs.readFile(filename, function(err, content) { if (!err) { response.write(content); } // Calling cb makes it go to the next item. cb(err); }); }, // Final callback after each item has been iterated over. function(err) { response.end() } ); }
If you want to accomplish this without a library, or just want another way, this is how I would do it more directly. Basically you keep a count
and call end
once both file reads have finished.
function css(response) { response.writeHead(200, {"Content-Type": "text/css"}); var count = 0; var handler = function(error, content){ count++; if (error){ console.log(error); } else{ response.write(content); } if (count == 2) { response.end(); } } fs.readFile('css/bootstrap.css', handler); fs.readFile('css/bootstrap-responsive.css', handler); }
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