Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reading and returning multiple files in Node.js using fs.readFile

Tags:

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(); } 
like image 900
hughesdan Avatar asked Feb 25 '12 21:02

hughesdan


People also ask

How do I send multiple files in node JS?

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.

Does readFile return anything?

readFile. Returns the contents of the file named filename. If encoding is specified then this function returns a string. Otherwise it returns a buffer.

What Is syntax of readFile () method?

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 )


1 Answers

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); } 
like image 189
loganfsmyth Avatar answered Sep 25 '22 12:09

loganfsmyth