zoukankan      html  css  js  c++  java
  • Express app.listen 函数了解

    最近一直在学习如何用原生的 Node.js 来做一个网站。在写的同时也在学习 Express 源码。

    一直觉得 Express 开启服务器的方法挺有趣的,就看了一下。

    在 Express 运行的时候会默认运行根目录下的 index.js,里面的源码也很简单:

    module.exports = require('./lib/express');
    

    看到其实运行了 lib/express 模块,追踪过去,看到了:

    exports = module.exports = createApplication;
    

    导出了 createApplication 这个方法:

    function createApplication() {
        var app = function(req, res, next) {
            app.handle(req, res, next);
        };
    
        mixin(app, EventEmitter.prototype, false);
        mixin(app, proto, false);
    
        app.request = { __proto__: req, app: app };
        app.response = { __proto__: res, app: app };
        app.init();
        return app;
    }
    

    首先定义了一个方法 app,方法有三个参数 reqresnext。然后在这个函数里面又执行了 app.handle 这个函数,这个函数后面说说,涉及到了路由。同时还涉及到了创建服务器函数,下面继续。

    再往下看看,会看到 mixin 这个函数,在最上面引入模块的时候,定义了这个函数名:

    var EventEmitter = require('events').EventEmitter;
    var mixin = require('merge-descriptors');
    var proto = require('./application');
    var Route = require('./router/route');
    var Router = require('./router');
    var req = require('./request');
    var res = require('./response');
    

    mixin 这个函数是引用了 merge-descriptors模块,嗯,到 node_module 里面找找,或者到 github 里面找找也可以。

    看源码,如果对原生JS的函数不是很熟悉的话,根本看不懂...不过我们可以到 MDN 里面查查,地址懒的贴。我也懒得去介绍里面的各种函数,这个模块的作用和 jQuery 里面的 $.extent 其实是一模一样的,将第二个参数的属性和属性值合并到第一个参数中,第三个参数如果是 false 则如果两个参数里面有属性一样,不允许覆盖,如果是 true,则覆盖第一个参数属性。

    由此可见:

    mixin(app, EventEmitter.prototype, false);
    mixin(app, proto, false);
    

    这两句话就很好懂了,就是将 EventEmitter.prototypeproto 的属性克隆给 app

    这里看到 proto 肯定也很郁闷...这玩意从哪里来的...还是往上面看:

    var proto = require('./application');
    

    额...又是一个模块,继续追踪,第一句话:

    var app = exports = module.exports = {};
    

    唉哟,又看到了 app,这 express 命名也是有趣,都是 app 。我再看的时候也很郁闷,完全会看混淆。继续往下看,原来这个模块的作用就是给 app 添加了各种属性和函数,各种核心函数...各种看不懂的函数...

    这里我们找到我们希望看到的一个 listen 这个函数:

    app.listen = function listen() {
        var server = http.createServer(this);
        return server.listen.apply(server, arguments);
    };
    

    好烦哟...又碰到看不懂的了,尼玛 this 是什么鬼!!!!我们从 Node.js 的 API 手册可以看到啊,明明官方都说了:

    The requestListener is a function which is automatically added to the 'request' event.
    

    this 这个参数的位置明明应该是一个函数啊,但是在 application 里面我们看到的 app 很显然就是一个 {} 对象啊,尼玛,怎么可能是一个 Function ?

    好吧,没办法,我们 console.log(this) 试试,看看返回的是什么:

    { [Function]
      domain: undefined,
      _events: { mount: [Function: onmount] },
      _maxListeners: undefined,
      setMaxListeners: [Function: setMaxListeners],
      getMaxListeners: [Function: getMaxListeners],
      emit: [Function: emit],
      addListener: [Function: addListener],
      on: [Function: addListener],
      once: [Function: once],
      removeListener: [Function: removeListener],
      removeAllListeners: [Function: removeAllListeners],
      listeners: [Function: listeners],
      listenerCount: [Function: listenerCount],
      init: [Function: init],
      defaultConfiguration: [Function: defaultConfiguration],
      lazyrouter: [Function: lazyrouter],
      handle: [Function: handle],
      use: [Function: use],
      route: [Function: route],
      ...
    

    第一句居然是 Function ,是什么鬼?什么时候变成了 Function ,仔细看一下,我们发现里面好像有 EventEmitter.prototype 的属性:

    EventEmitter {
        domain: undefined,
        _events: undefined,
        _maxListeners: undefined,
        setMaxListeners: [Function: setMaxListeners],
        getMaxListeners: [Function: getMaxListeners],
        emit: [Function: emit],
        addListener: [Function: addListener],
        on: [Function: addListener],
        once: [Function: once],
        removeListener: [Function: removeListener],
        removeAllListeners: [Function: removeAllListeners],
        listeners: [Function: listeners],
        listenerCount: [Function: listenerCount] }
    

    哎哟,不错哟,貌似发现了新大陆...明明在 application 这个模块没有添加这个属性啊,从哪里加的?这个时候我们应该顺其自然的想到了:

    mixin(app, EventEmitter.prototype, false);
    

    这句话,好像很突然的想到似的...是否在想明明在 express 这个模块加的,为啥在 application 里面会添加进去?OK,到了我们最关键的时候了,我们应该把 Express 的执行顺序理清楚了:

    • 在 CMD 或者 终端 执行:node app
    • 在我们自己写的 app.js 文件中执行 express(),这里就开始运行 express 模块了。
    • 进去 express 模块,运行 index.js
    • index.js 进去 lib/express.js
    • express.js 中执行 createApplication
    • createApplication 中首先定义了一个 app 的函数,其实刚才我们 console.log(this) 的时候,this 返回的就是这个 app 函数
    • 然后通过 mixin(app, EventEmitter.prototype, false);mixin(app, proto, false);EventEmitter.prototypeproto 里面的属性全部都加到 app 这个函数里面
    • 执行app.requestapp.response 这两个就是将重新定义的 requestresponse 加到 app 里面,这两个以后再说
    • 继续执行 app.init(); ,这句话就简单了啊,init 这个函数在 application.js 模块中,主要作用就是给 app 加一些初始化设置
    • 最后返回 app
    • 在我们自己写的 app.js 文件中获取到返回的 app,准备创建服务器 app.listen(3000)
    • 开始执行 app.listen 这个函数,在 app 中找到 listen,这个函数在 express.js 中已经从 proto 克隆到了 app 上了,所以,我们直接到 proto 中找 listen,也就是 application.js 中去找,找到之后就回到了我们最开始的问题:var server = http.createServer(this);this 是什么????看到这里,其实我们已经知道了,this 其实就是 var app = function(req,res,next){},OK到这里就结束了...

    这么晚写这文章,感觉写了一大坨废话...最后的执行顺序才是我最想说的

  • 相关阅读:
    HDFS集群优化篇
    JavaScript基础知识-流程控制之if语句
    JavaScript基础知识-代码块
    Linux下查看某个进程打开的文件数-losf工具常用参数介绍
    Linux下查看线程数的几种方法汇总
    Linux网卡调优篇-禁用ipv6与优化socket缓冲区大小
    UGUI Text(Label)
    Vuforia Android 6 Camera Error
    轻量级C#编辑器RoslynPad((基于Roslyn编译器))
    [AR]Vumark(下一代条形码)
  • 原文地址:https://www.cnblogs.com/fws407296762/p/5515821.html
Copyright © 2011-2022 走看看