Node.JS:处理大型节点应用程序

时间:2016-09-12 17:28:37

标签: javascript node.js design-patterns

我是Node.JS的新手,并开始寻找最佳实践文章等,以确保我的node.js代码是单元测试友好的,并遵循node.js最佳实践。在研究时我遇到了以下代码示例:

app.js:

module.exports = function (flights) {
    var express = require('express');
    var routes = require('./routes')(flights);
    var path = require('path'); 
    var app = express();

    // all environments
    app.set('port', process.env.PORT || 3000);
    app.set('views', __dirname + '/views');
    app.set('view engine', 'jade');
    app.use(express.favicon());
    app.use(express.logger('dev'));
    app.use(express.bodyParser());
    app.use(express.methodOverride());
    app.use(function (req, res, next) {
        res.set('X-Powered-By', 'Flight Tracker');
        next();
    });
    app.use(app.router);
    app.use(express.static(path.join(__dirname, 'public')));

    // development only
    if ('development' == app.get('env')) {
      app.use(express.errorHandler());
    }

    app.get('/flight/:number', routes.flight);
    app.put('/flight/:number/arrived', routes.arrived);
    app.get('/list', routes.list);

    return app;
}

server.js:

var http = require('http'),
    flights = require('./data'),
    app = require('./app')(flights);

http.createServer(app).listen(app.get('port'), function(){
  console.log('Express server listening on port ' + app.get('port'));
});

模块(index.js):

var Flight = function () {
    this.data = {
        number: null,
        origin: null,
        destination: null,
        departs: null,
        arrives: null,
        actualDepart: null,
        actualArrive: null
    };

    this.fill = function (info) {
        for(var prop in this.data) {
            if(this.data[prop] !== 'undefined') {
                this.data[prop] = info[prop];
            }
        }
    };

    this.triggerDepart = function () {
        this.data.actualDepart = Date.now();
    };

    this.triggerArrive = function () {
        this.data.actualArrive = Date.now();
    };

    this.getInformation = function () {
        return this.data;
    };
};

module.exports = function (info) {
    var instance = new Flight();

    instance.fill(info);

    return instance;
};

路由(index.js):

module.exports = function (flights) {
    var flight = require('../flight');

    for(var number in flights) {
        flights[number] = flight(flights[number]);
    }

    var functions = {};

    functions.flight = function(req, res){
        var number = req.param('number');

        if (typeof flights[number] === 'undefined') {
            res.status(404).json({status: 'error'});
        } else {
            res.json(flights[number].getInformation());
        }
    };

    functions.arrived = function (req, res) {
        var number = req.param('number');

        if (typeof flights[number] === 'undefined') {
            res.status(404).json({status: 'error'});
        } else {
            flights[number].triggerArrive();
            res.json({status: 'done'});
        }
    };

    functions.list = function (req, res) {
        res.render('list', {
            title: 'All Flights', 
            flights: flights});
    };

    return functions;
};

虽然我喜欢这种方式很有组织,但我没有看到在这种情况下处理多个模块的有效方法。假设我有用户,Initerary等的附加模块。当我开始向app.js文件添加路由时,这似乎很快就会变得混乱,更不用说需要将多少潜在参数传递到app.js 。如果我有一个需要20个或更多模块的大型休息层怎么办?我正在寻找任何doc或链接或示例,展示我应该在node.js中执行此操作的简洁方法。

2 个答案:

答案 0 :(得分:0)

使用express.Router()的子路由器进行粒化和封装。然后,每个路由器都会成为它自己的模块,这样您就不必在app.js中明确添加每一条路由。

<强> user.js的

"use strict";

// Create a router
var express = require("express"),
    router = express.Router();

router.get("/", function (req, res, next) {
    // All your User logic
    res.send([
        {
            name: "Bob"
        },
        {
            name: "John"
        }
    ]);
});

router.get("/:number", function (req, res, next) {
    res.send({
        name: "Bob"
    });
});

router.post("/", function (req, res, next) {
    res.send({
        name: "New Guy"
    });
});

module.exports = router;

<强> App.js

var app = express();
app.use("/user", require("./User"));

现在您可以GET /userGET /user/SOME_IDPOST/user。如果你想将子路径移动到其他地方也很简单,因为为用户路由定义的方法是相对的。

答案 1 :(得分:0)

我也有一个名为campaign_service的大型企业应用程序,由许多模块组成。

这就是我在文件campaign_router.js中组织路线的方法。

var express = require('express');
var router = express.Router();
var cm = require('./campaign_manager.js');
var qsc = require('./converters/qs_converter.js');
var jsc = require('./converters/json_converter.js');
var xmlc = require('./converters/xml_converter.js');
var fc = require('./converters/f_converter');
var fc2 = require('./converters/fjt2_converter');
var cv = require('./campaign_validator.js');
var templates = require('./template_list.js');
var AuthDecoder = require('authdecoder');
var adc = AuthDecoder.middleware;

router.get    ('/campaigns/qs',     qsc, adc, cv, cm.createCampaign);       // Creates a new campaign using query string params
router.post   ('/campaigns/b/xml',  xmlc, adc, cv, cm.createCampaign);      // Creates a new campaign using xml payload
router.post   ('/campaigns/file',   fc, adc, cv, cm.createCampaign);        // Creates a new campaign using uploaded file
router.post   ('/campaigns/file/type2',   fc2, adc, cv, cm.createCampaign); // Creates a new campaign using uploaded file
router.post   ('/campaigns/js',     jsc, adc,cv, cm.createCampaign);        // Creates a new bulk campaign using json payload
router.get    ('/campaigns/',       adc, cm.getCampaigns);                  // Returns  a list of bulk campaigns accessible for the invoking user.
router.get    ('/campaigns/date',   adc, cm.getCampaignsByRange);           // Returns  a list of bulk campaigns accessible for the invoking user.
router.get    ('/campaigns/b/:id',  adc, cm.getCampaign);                   // returns the details of a specific campoaign
router.put    ('/campaigns/b/id',   cm.updateCampaign);                     // Updates a specified campaign
router.delete ('/campaigns/b/:id',  cm.deleteCampaign);                     // deletes a campaign
router.post   ('/pause',            adc, cm.pauseJob);                      // Pauses an ongoing campaign
router.post   ('/resume',           adc, cm.resumeJob);                     // Resumes a paused campaign
router.post   ('/cancel',           adc,cm.cancelJob);                      // Resumes a paused campaign
//router.post   ('/reschedule',       adc,cm.rescheduleCampaign);             // Resumes a paused campaign
//router.get    ('/',                 cm.pingCampaignServer);    
router.get    ('/templates',        adc, templates.listTemplates);          // gives the campaign server templates

突出点:

  • 所有广告系列功能,进入另一个js文件(这是一个中间件),名为campaign_manager.js
  • 所有有效负载转换器都会进入名为&#34; converter&#34;的子文件夹,此文件夹中有许多名为&#39; qs_converter.js&#39;&#39; json_converter.js&#39; ,...,等等等等。
  • 我的应用会在接受任何广告系列请求之前执行身份验证,因此路由中会加载中间件。
  • 如果除了&#34; / campaigns&#34;之外还有其他挂载点,我会创建另一个路由器模块并定义其他.js文件。 _我会使用index.js(或app.js)来加载这些路由器。

基本上,我很容易将代码扩展到多个模块并通过路由器文件导入它们。

修改 添加了使用场景 Index.js

var routes = require('./campaign_router.js');
...
app.use('/campaignservice', routes);