简体   繁体   中英

Loading multiple files synchronously in node.js

I am learning node.js and have build a micro-app around an MVC architecture.

I have a router.js file which loads a controller based on the URI, which, in most cases, would load the views using the "fs" module. The views being the HTML elements making up the web page (basically head, body, & footer) as 3 separate files .

Here is the code for the controller:

var load_view = 'test.html';

function data(response, request, fs){ 

    response.writeHead(200, {"Content-Type": "text/html"});

    var count = 0;
    var handler = function(error, content){

        count++;
        if(error)   console.log(error);
        else        response.write(content);

        if(count==3) response.end();

    }

    fs.readFile('view/elements/head.html', handler);  // should load 1st
    fs.readFile('view/'+load_view, handler);          // should load 2nd
    fs.readFile('view/elements/footer.html', handler);// should load 3rd

}

exports.data = data;

As you can see the HTML elements are supposed to load in order (head.html, then the particular view for this controller - test.html, then footer.html). But they sometimes do NOT.

They load in the "head, body, footer" order most of the time.

Sometimes they load as "head, footer, body".

Other times its "body, head, footer".

They never seem to load in any other configuration.

Please see screenshots attached.

头,身体,页脚

头,页脚,身体

身体,头部,页脚

Im am not sure what is happening here. Why are these files being loaded in any order but the one they are called??

  • Please note I am intentially not using a framework like Express.js for learning purposes

You cannot make assumptions about the ordering of responses for asynchronous requests. There are various factors that could affect this ordering (eg OS thread scheduling in the case of filesystem requests).

So the solution to this is to either call them serially by nesting callbacks or chaining Promises or by using a module like async , or bind your callbacks to include relevant contextual information so you know which file just got loaded in your callback. An example of the latter might be something like:

function data(res, req, fs) {
  // Files to be loaded, in the order to be written to the response
  var files = [
    'view/elements/head.html',
    'view/' + load_view,
    'view/elements/footer.html'
  ];

  // Start read requests, each with a callback that has an extra
  // argument bound to it so it will be unshifted onto the callback's
  // parameter list
  for (var i = 0; i < files.length; ++i)
    fs.readFile(files[i], handler.bind(null, i));

  var count = 0;
  function handler(index, err, content) {
    // Make sure we don't send more than one response on error
    if (count < 0)
      return;

    if (err) {
      count = -1;
      console.log('Error for file: ' + files[index]);
      console.log(err);
      res.writeHead(500);
      return res.end();
    }

    // Reuse our `files` array by simply replacing filenames with
    // their respective content
    files[index] = content;

    // Check if we've read all the files and write them in order if
    // we are finished
    if (++count === files.length) {
      res.writeHead(200, { 'Content-Type': 'text/html' });
      for (var i = 0; i < files.length; ++i)
        res.write(files[i]);
      res.end();
    }
  }
}

On a related note, you might look into using a templating system (that supports including partials (like headers and footers) and layouts) of some kind to avoid doing this kind of manual work.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM