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??
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.