express學(xué)習(xí)筆記

Express簡介

是一個(gè)簡潔、靈活的node.js Web應(yīng)用開發(fā)框架,是目前最流行的基于Node.js的Web開發(fā)框架. 它提供一系列強(qiáng)大的功能,比如:

  • 模板解析
  • 靜態(tài)文件服務(wù)
  • 中間件
  • 路由控制
    還可以使用其他模塊來幫助你創(chuàng)建各種Web和移動(dòng)設(shè)備應(yīng)用

簡單創(chuàng)建一個(gè)express

首先需要提供一個(gè)工廠函數(shù),創(chuàng)建app,之后的多項(xiàng)功能將在該app對象上添加

function createApplication(){
  let app = function(req,res){};
  return app;
}

路由實(shí)現(xiàn)

express一個(gè)最重要的功能即是定義路由規(guī)則,通過對這些規(guī)則的匹配返回不同的內(nèi)容
首先我們需要一種叫router(路由容器)的東西來存放具體的route

const Route = require('./route');
const Layer = require('./layer');
const url = require('url');
const methods = require('methods');
const init = require('../middle/init');
const slice = Array.prototype.slice;
//let r = Router()
//let r = new Router();
function Router() {
    function router(req, res, next) {
        router.handle(req, res, next);
    }
    Object.setPrototypeOf(router, proto);
    router.stack = [];
    //聲明一個(gè)對象,用來緩存路徑參數(shù)名它對應(yīng)的回調(diào)函數(shù)數(shù)組
    router.paramCallbacks = {};
    //在router一加載就會(huì)加載內(nèi)置 中間件
    // query
    router.use(init);
    return router;
}
let proto = Object.create(null);
//創(chuàng)建一個(gè)Route實(shí)例,向當(dāng)前路由系統(tǒng)中添加一個(gè)層
proto.route = function (path) {
    let route = new Route(path);
    let layer = new Layer(path, route.dispatch.bind(route));
    layer.route = route;
    this.stack.push(layer);

    return route;
}
proto.use = function (path, handler) {
    if (typeof handler != 'function') {
        handler = path;
        path = '/';
    }
    let layer = new Layer(path, handler);
    layer.route = undefined;//我們正是通過layer有沒有route來判斷是一個(gè)中間件函數(shù)還是一個(gè)路由
    this.stack.push(layer);
}
methods.forEach(function (method) {
    proto[method] = function (path) {
        let route = this.route(path);//是在往Router里添一層
        route[method].apply(route, slice.call(arguments, 1));
        return this;
    }
});
proto.param = function (name, handler) {
    if (!this.paramCallbacks[name]) {
        this.paramCallbacks[name] = [];
    }
    // {uid:[handle1,hander2]}
    this.paramCallbacks[name].push(handler);
}
/**
 * 1.處理中間件
 * 2. 處理子路由容器 
 */
proto.handle = function (req, res, out) {
    //slashAdded是否添加過/ removed指的是被移除的字符串
    let idx = 0, self = this, slashAdded = false, removed = '';
    // /user/2
    let { pathname } = url.parse(req.url, true);
    function next(err) {
        if (removed.length > 0) {
            req.url = removed + req.url;
            removed = '';
        }
        if (idx >= self.stack.length) {
            return out(err);
        }
        let layer = self.stack[idx++];
        //在此匹配路徑 params   正則+url= req.params
        if (layer.match(pathname)) {// layer.params
            if (!layer.route) { //這一層是中間件層//  /user/2
                removed = layer.path;//  /user
                req.url = req.url.slice(removed.length);// /2
                if (err) {
                    layer.handle_error(err, req, res, next);
                } else {
                    layer.handle_request(req, res, next);
                }
            } else {
                if (layer.route && layer.route.handle_method(req.method)) {
                    //把layer的parmas屬性拷貝給req.params
                    req.params = layer.params;
                    self.process_params(layer, req, res, () => {
                        layer.handle_request(req, res, next);
                    });
                } else {
                    next(err);
                }
            }
        } else {
            next(err);
        }
    }
    next();
}
//用來處理param參數(shù),處理完成后會(huì)走out函數(shù)
proto.process_params = function (layer, req, res, out) {
    let keys = layer.keys;
    let self = this;
    //用來處理路徑參數(shù)
    let paramIndex = 0 /**key索引**/, key/**key對象**/, name/**key的值**/, val, callbacks, callback;
    //調(diào)用一次param意味著處理一個(gè)路徑參數(shù)
    function param() {
        if (paramIndex >= keys.length) {
            return out();
        }
        key = keys[paramIndex++];//先取出當(dāng)前的key
        name = key.name;// uid
        val = layer.params[name];
        callbacks = self.paramCallbacks[name];// 取出等待執(zhí)行的回調(diào)函數(shù)數(shù)組
        if (!val || !callbacks) {//如果當(dāng)前的key沒有值,或者沒有對應(yīng)的回調(diào)就直接處理下一個(gè)key
            return param();
        }
        execCallback();
    }
    let callbackIndex = 0;
    function execCallback() {
        callback = callbacks[callbackIndex++];
        if (!callback) {
            return param();//如果此key已經(jīng)沒有回調(diào)等待執(zhí)行,則意味本key處理完畢,該執(zhí)行一下key
        }
        callback(req, res, execCallback, val, name);
    }
    param();
}
module.exports = Router;
/**
 * Router
 *   stack
 *      layer
 *         path route
 *                 method handler
 * Layer
 * Router Layer 路徑 處理函數(shù)(route.dispatch) 有一個(gè)特殊的route屬性
 * Route  layer  路徑 處理函數(shù)(真正的業(yè)務(wù)代碼)  有一特殊的屬性method
 */

 /**
  * 1.params param
    2.模板引擎 我們會(huì)自己寫一個(gè)模板支持,邏輯判斷 。if while do
  */
 

未完待續(xù)……

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容