MVC in node and general: How are models tied to vi

2019-04-09 14:59发布

I'm starting with node.js and am making a simple MVC framework. So far, I've got a front controller (or 'dispatcher', if you will) working. The routing happens through a dispatcher config module, as shown.

My questions are at the end, immediately after the code. Also, this is an exercise in learning to node, please do not suggest express.js and the likes.

dispatcherConfig.js:

var url = require('url');

(function() {
    var dispatcherConfig = {
        '/'                 : 'homeController',
        '/index.html'       : 'homeController',
        '/sayHello.html'    : 'helloController',
        '404'               : '404Controller'
    };

    module.exports.getController = function(request) {
        var route = url.parse(request.url, true).pathname;
        if(dispatcherConfig[route]) {
            return dispatcherConfig[route];
        }
        return dispatcherConfig['404'];
    }
}());


This is used by dispatcher.js:

var dispatcherConfig = require('./config/dispatcherConfig');

(function() {
    module.exports.dispatch = function(request, response) {
        var requiredController = dispatcherConfig.getController(request);
        var controller = require('./controllers/' + requiredController);
        controller.doService(request, response);
    }
}());


And here is what a sample controller looks like (works dandy too) - homeController.js:
(Please ignore the inline view code for now)

(function() {
    var homeController = {
        doService: function(request, response) {
            response.write('<form action="/sayHello.html" method="GET">' + 
                '<input id="name" name="name" size="20" />' + 
                '<input type="submit" value="Submit" />' + 
                '</form>');
        }
    }

    module.exports.doService = function(request, response) {
        return homeController.doService(request, response);
    }
}());


This routing works nicely. I've got controllers easily wiring up to url patterns, and am emulating spring's multiaction controller type as well, by further inspecting the request object.

Three obvious things that need to be done here are:

  1. Creating view objects
  2. Creating model objects
  3. Binding views and models


Questions:

  1. In MVC (spring at least), it's controllers that bind a view with a model. Is this the best way of doing it? What if I maintain separate a separate configuration which describes what view binds to what model, and the controller only routes to a view. Is this wrong and not MVC?

  2. What is a good way to represent a view in node.js? Since it is heavily template based, what templating options are on offer (matured ones)?

  3. If I load a file to be served statically (say CSS file, loaded through file read into memory), and I keep a reference to the contents in the global/app scope, then subsequent requests can be served directly from memory, resulting in phenomenal speeds, is this assumption correct? In fact, we can guarantee that after the first request entering the node server (which will trigger the file read and the contents being loaded into mem), all subsequent requests will be served from memory (for such static content).

  4. What is the low level (framework-less) way of grabbing POST data in raw node.js?

Thanks.

2条回答
神经病院院长
2楼-- · 2019-04-09 15:53

The most commonly-used templating engines I've seen used with node are Jade and EJS, largely because Express has built-in support for them. If you're not going to use Express, I'd also seriously look into Mustache (I personally prefer its philosophy to Jade/EJS).

查看更多
Deceive 欺骗
3楼-- · 2019-04-09 15:56

To answer your title question, this is how I had it explained to me:

The controller is the router, it takes incoming requests, pairs them up with some business logic (that includes fetching data), and some rendering method, and then spits them back out the queue. Think of it as a mail sorter or something: "Here's an address, there's a bin".

The view is supposed to be dumb. It's supposed to take data and stuff it into slots and maybe do some loops for tables, and maybe include some other views, but that's about it. Render HTML. Even better is the "view" that "renders" XML or JSON output, or just raw data back to the client. (all views)

The Model is the tricky part, because that's where you process data coming in, or results coming from the database. So there may be many "layers" here, and you may actually make many nested calls. This is where you're going to validate inputs beyond sanity checks (and return appropriate carrier messages back up to the controller on failures), this is where you're going to preprocess before storage, and postprocess what came out of the database. This is where the logic lives.

Here's the thing: We're not doing things monolithically anymore, we're calling what we intend to have happen. So by calling a specific controller, you've already specified some information, semantically (see why they call it the semantic web, because of this).

So we can afford to make the controller dumber (the caller knows the intent). We can afford to make the model dumber (it's handling a specific bit of business logic and storage for the controller). And the view was always dumb.

That's not to say that a single model class can't be quite large. But the part that the individual controller should call should be narrow.

For your other requests:

In MVC (spring at least), it's controllers that bind a view with a model. Is this the best way of doing it? What if I maintain separate a separate configuration which describes what view binds to what model, and the controller only routes to a view. Is this wrong and not MVC?

See above, I think I already covered this. A controller is requested to do a certain thing based on what you semantically want. A controller is not a monolithic switch statement, so there's no need to have lots of configuration happening therein.

What is a good way to represent a view in node.js? Since it is heavily template based, what templating options are on offer (matured ones)?

"represent a view"? Um, view engines do the matching up on their own. Do you really want to write your own view engine? It can be done. Tokenize a viewfile, find the "control verbs" (for lack of a better name, I'm sure they have one), insert data there, then render the entire tokenized structure back out as a string (HTML is inherently a string, no?). That's all I got for a nutshell. My advice is, let the view people do the view work, you don't need to rewrite them all.

If I load a file to be served statically (say CSS file, loaded through file read into memory), and I keep a reference to the contents in the global/app scope, then subsequent requests can be served directly from memory, resulting in phenomenal speeds, is this assumption correct? In fact, we can guarantee that after the first request entering the node server (which will trigger the file read and the contents being loaded into mem), all subsequent requests will be served from memory (for such static content).

That is a correct assumption. That is what I would do, with a general garbage collection routine to check every few minutes and shred any file older than n minutes, and then reload on subsequent requests, ensuring that you're getting relatively recent files. But this is effectively what caching proxies do, so yes, that's perfectly acceptable.

What is the low level (framework-less) way of grabbing POST data in raw node.js?

You don't. Node does this for you. It's presented in the request object already.

查看更多
登录 后发表回答