nodejs express 框架解密2-如何创建一个app

本文是基于express 3.4.6 的

1.在我们的app.js 文件里面有这么几行

 

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

这个其实是调用http模块 的 createServer 函数创建一个服务,然后监听端口的。

2. 我们再去看看express 的入口文件 

/**
 * Module dependencies.
 */

var connect = require('connect')
  , proto = require('./application')
  , Route = require('./router/route')
  , Router = require('./router')
  , req = require('./request')
  , res = require('./response')
  , utils = connect.utils;

/**
 * Expose `createApplication()`.
 */

exports = module.exports = createApplication;

/**
 * Expose mime.
 */

exports.mime = connect.mime;

/**
 * Create an express application.
 *
 * @return {Function}
 * @api public
 */

function createApplication() {
  var app = connect();
  //将application中的方法全部拷贝到connect对象上去。
  utils.merge(app, proto);
  //设置app 的request对象的原型为req,本身的属性为connect对象
  app.request = { __proto__: req, app: app };
  //设置app的response对象原型为res ,本身的属性为connect对象
  app.response = { __proto__: res, app: app };
  //调用application中的方法init
  app.init();
  return app;
}

/**
 * Expose connect.middleware as express.*
 * for example `express.logger` etc.
 */
/**
 * 加载connect模块中得所有中间件
 */
for (var key in connect.middleware) {
  Object.defineProperty(
      exports
    , key
    , Object.getOwnPropertyDescriptor(connect.middleware, key));
}

/**
 * Error on createServer().
 */
/**
 *  将创建服务器的方法输出
 * @returns {Function}
 */
exports.createServer = function(){
  console.warn('Warning: express.createServer() is deprecated, express');
  console.warn('applications no longer inherit from http.Server,');
  console.warn('please use:');
  console.warn('');
  console.warn('  var express = require("express");');
  console.warn('  var app = express();');
  console.warn('');
  //加载创建应用程序的方法,开始创建application
  return createApplication();
};

/**
 * Expose the prototypes.
 */

exports.application = proto;
exports.request = req;
exports.response = res;

/**
 * Expose constructors.
 */

exports.Route = Route;
exports.Router = Router;

// Error handler title

exports.errorHandler.title = 'Express';

可以看到exports = module.exports = createApplication;将这个作为模块导出了,作为一个构造函数。

这个函数是: 

function createApplication() {
  var app = connect();
  //将application中的方法全部拷贝到connect对象上去。
  utils.merge(app, proto);
  //设置app 的request对象的原型为req,本身的属性为connect对象
  app.request = { __proto__: req, app: app };
  //设置app的response对象原型为res ,本身的属性为connect对象
  app.response = { __proto__: res, app: app };
  //调用application中的方法init
  app.init();
  return app;
}

首先调用connect 组件app,于是将proto 上该有的方法都拷贝到app上去。proto是神马么?它就是  proto = require('./application')  application.js 输出的“app” 对象 所有得函数,

接着将req,res 作为 组件app 的request,response 的原型,同时将app作为他们的一个属性,为什么要这么做呢?后面就会看到。最后调用app.init()方法,这个其实是调用application

中的init方法。

3.application.js 

app.init = function(){
  this.cache = {};
  this.settings = {};
  this.engines = {};
  //默认配置
  this.defaultConfiguration();
};

我们看到他是直接调用defaultConfiguration 方法的。我们再去看看defaultConfiguration方法的实现

app.defaultConfiguration = function(){
  // default settings
  this.enable('x-powered-by');
  this.enable('etag');
  this.set('env', process.env.NODE_ENV || 'development');
  this.set('subdomain offset', 2);
  debug('booting in %s mode', this.get('env'));

  // implicit middleware
  //调用中间件
  this.use(connect.query());
  this.use(middleware.init(this));

  // inherit protos
  //继承原型
  this.on('mount', function(parent){
    this.request.__proto__ = parent.request;
    this.response.__proto__ = parent.response;
    this.engines.__proto__ = parent.engines;
    this.settings.__proto__ = parent.settings;
  });

  //router
  //路由
  this._router = new Router(this);
  this.routes = this._router.map;
  this.__defineGetter__('router', function(){
    this._usedRouter = true;
    this._router.caseSensitive = this.enabled('case sensitive routing');
    this._router.strict = this.enabled('strict routing');
    return this._router.middleware;
  });

  // setup locals
  this.locals = locals(this);

  // default locals
  this.locals.settings = this.settings;

  // default configuration
  this.set('view', View);
  this.set('views', process.cwd() + '/views');
  this.set('jsonp callback name', 'callback');

  this.configure('development', function(){
    this.set('json spaces', 2);
  });

  this.configure('production', function(){
    this.enable('view cache');
  });
};

从代码中可以看到,它首先调用中间件,中间件的作用主要是改写改写request,response 请求的。将这2个请求导出,方便后面的模板渲染。然后再调用路由模块。路由模块只要是根据path

调用路由分发函数分发路由,执行callback,最后调用view 模块,渲染我们的模板。

posted @ 2013-12-19 10:42  yupeng  阅读(5240)  评论(0编辑  收藏  举报