Express核心原理

逐行解析Express核心原理

文章主要以一下三個(gè)部分組成

  1. node 創(chuàng)建http服務(wù)
  2. express 創(chuàng)建http服務(wù)
  3. 自己寫(xiě)類(lèi)express并且解析核心原理

1. node創(chuàng)建http 服務(wù)

基于node基本的創(chuàng)建服務(wù)

//引入node 模塊
const http = require('http')
//創(chuàng)建服務(wù),并且實(shí)現(xiàn)callback回調(diào)
const server = http.createServer(callback)
const callback = (req,res) =>{
    res.end("Hello xie")
}
//服務(wù)監(jiān)聽(tīng)3000 端口
server.listen(3000)

上面我們用最原始的方式 創(chuàng)建一個(gè)服務(wù),當(dāng)訪問(wèn)localhost:3000即可返回相關(guān)數(shù)據(jù)

2. 使用express 創(chuàng)建服務(wù)

    npm install express --save
    
    const express = require('express')
    const app = express()
    const port = 3000
    
    //路由
    app.get('/', (req, res) => res.send('Hello World!'))
    app.listen(port, () => console.log(`Example app listening on port ${port}!`))

使用express的優(yōu)勢(shì)在于其可以使用中間件,這也是其核心,所謂的中間件,其實(shí)也即使一個(gè)函數(shù)function

/**
    定義一個(gè)中間件,
    暫且忽略next是啥,知道next是一個(gè)往下傳遞的方法即可
*/
const middle = (req,res,next) =>{
    //do something
    next()
}

app.use(middle)
app.use("/api",middle, (req,res,next)=>{
    //dosomething
    next()
})

app.get(參數(shù)類(lèi)似use參數(shù))
app.post(參數(shù)類(lèi)似use參數(shù)){
    res.json({
        name:'xieyusheng'
    })
}
......

那么問(wèn)題來(lái)了,app.use/get/post/res.json以及最至關(guān)重要的next是怎么實(shí)現(xiàn)的呢?

3.自己寫(xiě)個(gè)Express框架

姑且就叫XExpress

1. 先定義接結(jié)構(gòu)
const http = require('http')
class XExpress{
    
    use () {
    }
    get () {
    }
    post () {
    }
    callback (){
    }
    listen(...argus){
        const server = http.createServer(callback)
        server.listen(...argus)
    }
}
module.exports = () => new Exprerss()

實(shí)例化

   const xErpress = './xExpress'
   const server = new xErpress()
   server.listen(3000)
   

ok,基本服務(wù)啟動(dòng)好了,那么use/get等怎么處理呢,這里核心原理來(lái)了哦,其實(shí)我們只要將所有的中間件函數(shù)放在一個(gè)棧中,然后一個(gè)一個(gè)執(zhí)行處理,那么怎么一個(gè)個(gè)處理呢? 使用next函數(shù)

    2. 將所有的中間件放在堆棧中
    //new XExpress 實(shí)例化一個(gè)單量
    constructor(){
        //存放中間件的list
        this.routes = {
            use: [],   // app.use(...)
            get: [],   // app.get(...)
            post: []   // app.post(...)
        }
    }
    //結(jié)構(gòu)化傳遞來(lái)的參數(shù)
    register (path) {
      const info = {};
      if(typeof path == "string"){
      info.path = path;
      //將后面的方法以arr的方式,放入內(nèi)存中,從第二個(gè)參數(shù)開(kāi)始
      info.stack = slice.call(arguments, 1)
    }else{
      info.path = "/" //當(dāng)use等方法的第一個(gè)參數(shù)是否是鏈接
      //從第一個(gè)參數(shù)開(kāi)始,轉(zhuǎn)換為數(shù)組,存入 stack
      info.stack = slice.call(arguments, 1)
    }

     return info;
     // info={
     //   path:'/',
     //   stack:[
     //     ()=>{};
     //     ()=>{}
     //   ]
     // }
    }
    use(){
     const info = this.register.apply(this, arguments)
     this.routes.all.push(info)
  }
  ....get/post類(lèi)似

所有的中間件都賦予在routes里面,那么當(dāng)請(qǐng)求來(lái)了,我們匹配下,然后一個(gè)個(gè)的執(zhí)行

callback(req,res) => {
    //定義方法給req
    req.json= () =>{
        // 定義返回格式
        res.setHeader("Contype-type" : "application/json")
        res.end(
            JSON.stringify(data)
         )
    }
    //1.匹配相對(duì)的中間件
       const url = req.url
       const method = req.method.toLowerCase()
       //匹配
       const resultList = this.match(method, url)
      
      //一個(gè)一個(gè)的執(zhí)行中間件函數(shù)
         this.actionNext(req, res, resultList)
        
}

    /**
    根據(jù)url和method匹配相對(duì)應(yīng)的中間件LIST
    */
    match(method, url) {
        let stack = []
          // 獲取 routes
        let curRoutes = []
        curRoutes =[...this.routes.use]
        curRoutes = [...this.routes.use[method]]
        curRoutes.forEach(routeInfo => {
            if (url.indexOf(routeInfo.path) === 0) {
                stack = stack.concat(routeInfo.stack)
            }
        })
        return stack
    }

    actionNext(req, res, stack){
            // 定義next函數(shù)
          const next = () =>{
                const middleware = stack.shift() //取出第一個(gè)
                if(middleware) {
                    //將next 函數(shù)傳遞
                    middleware(req,res,next)
                }
       }
       next();
    }

這樣,next函數(shù)傳遞給每個(gè)中間函數(shù)了,這里的next函數(shù)就是下一個(gè)要執(zhí)行函數(shù)的包裝體

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

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

  • 解析Koa2核心原理(手寫(xiě)KOA框架并解析) 前言:相對(duì)于express框架,koa框架只是提供了async/aw...
    謝玉勝閱讀 1,036評(píng)論 0 0
  • Express官網(wǎng)說(shuō):Express是基于 Node.js 平臺(tái)的 web 開(kāi)發(fā)框架。這句話包含了兩個(gè)部分內(nèi)容,一...
    喬治yuanbo閱讀 1,448評(píng)論 0 2
  • 引用:https://github.com/WangZhechao/expross 1.簡(jiǎn)介 這篇文章是分析exp...
    宮若石閱讀 3,245評(píng)論 1 8
  • 1. 簡(jiǎn)介 這篇文章主要的目的是分析理解express的源碼,網(wǎng)絡(luò)上關(guān)于源碼的分析已經(jīng)數(shù)不勝數(shù),這篇文章準(zhǔn)備另辟蹊...
    沒(méi)事造輪子閱讀 1,476評(píng)論 0 8
  • node-interview-questions Node是搞后端的,不應(yīng)該被被歸為前端,更不應(yīng)該用前端的觀點(diǎn)去理...
    IT楊閱讀 573評(píng)論 0 5

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