zoukankan      html  css  js  c++  java
  • 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 模块,渲染我们的模板。

  • 相关阅读:
    DropDownList控件的AutoPostBack属性的问题 选择后,值也跟着刷新 Kenny
    window showModalDialog 在IE6 IE7 高度(height) 问题 Kenny
    discuz初玩之一 未将对象引用设置到对象的实例(Discuz.Forum.HttpModule.ReUrl_BeginRequest) Kenny
    最长公共子串问题 LCS
    HDOJ 1024
    项目一周工作总结
    DartCloud技术难点、问题及经验教训
    中国云项目遇到的问题
    我的计算机书单
    翻转句子中单词的顺序 面试题
  • 原文地址:https://www.cnblogs.com/yupeng/p/3481679.html
Copyright © 2011-2022 走看看