Originally Posted by
MutantJohn
I'm scared that if I use Node.js, that main thread will quickly become over-saturated with user instructions.
As I understand it, all Node's really good at is instruction layering with the main thread. You have a single-thread but somehow through the divine magic of animal sacrifice, you have the ability to layer instructions in a much more efficient way so you can receive more page requests while you're fetching the pages of a previous request. Seems very well-designed but generating the HTML I need dynamically would be blocking which makes Apache + PHP seem more ideal.
Thoughts?
I have actually thought of recommending NodeJS to you before, but I wasn't sure how demanding the generation of your content would be. Like Soma says, everything in NodeJS happens (or appears to happen) asynchronously, but the code you run, like generating tables or doing math etc will be done in synchronous fashion. JavaScript itself is quite slow (I've run into this problem after implementing a SAT collision mechanism in my JS game engine), but because all the IO is asynchronous, it probably beats the alternatives given you aren't calculating PI for several minutes in your request handler lol.
Originally Posted by
MutantJohn
Edit : It seems like Express can be configured to handle all GET requests so every time a user wants to GET a URL and the URL is a valid directory path, I guess I can just generate the HTML from that. I think I'm doing that thing where I massively overly-complicate things in my head before I even try to do what it is I'm thinking of doing.
It sounds like you are talking about something I've heard called a "software router". I don't know if it will help, but below is some code from the book "Eloquent JavaScript", that implements a very basic software router (an unaltered version), with comments by myself. Basically the purpose is allow the user to associate a pattern to search requests for, with a callback function to be invoked when a match is found:
Code:
module.exports = (function () {
"use strict";
var Router = function () {
this.routes = [];
};
// Add a 'route' to the software router, where a 'route' should contain parts:
// 1. method : the HTTP method that we want to handle.
// 2. pattern : A regular expression that will be used to test incomming requests.
// 3. handler : A callback function to be executed if any incomming requests match the pattern
Router.prototype.add = function (method, pattern, handler) {
this.routes.push({method: method, pattern: pattern, handler: handler});
};
Router.prototype.resolve = function (request, response) {
// extract the path from the request url using 'url' module's 'parse' method
var path = require("url").parse(request.url).pathname;
// Return true if any routes in the array can resolve the path
return this.routes.some(function (route) {
// Use the routes regular expression to get matching parts in the requested path
var match = route.pattern.exec(path),
urlParts;
// Return false if no matches were found, or if the request type differs from the route type
if (!match || route.method !== request.method) {
return false;
}
// The first match in the array created by 'exec' is the full path,
// The rest of the matches are transformed by decoding the URL encoding
// and stored in a new array.
urlParts = match.slice(1).map(decodeURIComponent);
// The callback function is envoked with request, response, and all the pathway matches as arguments
route.handler.apply(null, [request, response].concat(urlParts));
return true;
});
};
return Router;
}());
This is meant to be run as part of a request handler, for instance after adding some routes, you would test them in your request handler like this:
Code:
function requestHandler (request, response) {
// If our router doesn't resolve the request, pass it to the file server.
if (!router.resolve(request, response)) {
serveFile(request, response);
}
}
It might be unnecessary to write it into your request handler though, if you instead 'subclass' the request handler (save a copy of the the current request handler and call it when resolving url fails). I dislike doing this on my own, because you need to be aware of what's happening or you might overwrite your modules handler by attaching a new one.
Some modules will do this though, for instance if you look around line 113 in the socket.io's 'manager' module:
Code:
// reset listeners
this.oldListeners = server.listeners('request');
server.removeAllListeners('request');
server.on('request', function (req, res) {
self.handleRequest(req, res);
});
Back on topic though, keep in mind that the 'Router' module from Eloquent JavaScript is very basic, and does no error checking whatsoever, but I think it illustrates the point. An example of how you might register a pathway handler from the same book:
Code:
// Register a handler to be invoke on "GET" requests that have a pathway that looks like "/talks/*"
router.add("GET", /^\/talks\/([^\/]+)$/, function(request, response, title) {
if (title in talks)
respondJSON(response, 200, talks[title]);
else
respond(response, 404, "No talk '" + title + "' found");
});
Hope anything of that was helpful, good luck!