Express核心原理

逐行解析Express核心原理

文章主要以一下三个部分组成

  1. node 创建http服务
  2. express 创建http服务
  3. 自己写类express并且解析核心原理

1. node创建http 服务

基于node基本的创建服务

//引入node 模块
const http = require('http')
//创建服务,并且实现callback回调
const server = http.createServer(callback)
const callback = (req,res) =>{
    res.end("Hello xie")
}
//服务监听3000 端口
server.listen(3000)

上面我们用最原始的方式 创建一个服务,当访问localhost:3000即可返回相关数据

2. 使用express 创建服务

    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的优势在于其可以使用中间件,这也是其核心,所谓的中间件,其实也即使一个函数function

/**
    定义一个中间件,
    暂且忽略next是啥,知道next是一个往下传递的方法即可
*/
const middle = (req,res,next) =>{
    //do something
    next()
}

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

app.get(参数类似use参数)
app.post(参数类似use参数){
    res.json({
        name:'xieyusheng'
    })
}
......

那么问题来了,app.use/get/post/res.json以及最至关重要的next是怎么实现的呢?

3.自己写个Express框架

姑且就叫XExpress

1. 先定义接结构
const http = require('http')
class XExpress{
    
    use () {
    }
    get () {
    }
    post () {
    }
    callback (){
    }
    listen(...argus){
        const server = http.createServer(callback)
        server.listen(...argus)
    }
}
module.exports = () => new Exprerss()

实例化

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

ok,基本服务启动好了,那么use/get等怎么处理呢,这里核心原理来了哦,其实我们只要将所有的中间件函数放在一个栈中,然后一个一个执行处理,那么怎么一个个处理呢? 使用next函数

    2. 将所有的中间件放在堆栈中
    //new XExpress 实例化一个单量
    constructor(){
        //存放中间件的list
        this.routes = {
            use: [],   // app.use(...)
            get: [],   // app.get(...)
            post: []   // app.post(...)
        }
    }
    //结构化传递来的参数
    register (path) {
      const info = {};
      if(typeof path == "string"){
      info.path = path;
      //将后面的方法以arr的方式,放入内存中,从第二个参数开始
      info.stack = slice.call(arguments, 1)
    }else{
      info.path = "/" //当use等方法的第一个参数是否是链接
      //从第一个参数开始,转换为数组,存入 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类似

所有的中间件都赋予在routes里面,那么当请求来了,我们匹配下,然后一个个的执行

callback(req,res) => {
    //定义方法给req
    req.json= () =>{
        // 定义返回格式
        res.setHeader("Contype-type" : "application/json")
        res.end(
            JSON.stringify(data)
         )
    }
    //1.匹配相对的中间件
       const url = req.url
       const method = req.method.toLowerCase()
       //匹配
       const resultList = this.match(method, url)
      
      //一个一个的执行中间件函数
         this.actionNext(req, res, resultList)
        
}

    /**
    根据url和method匹配相对应的中间件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函数
          const next = () =>{
                const middleware = stack.shift() //取出第一个
                if(middleware) {
                    //将next 函数传递
                    middleware(req,res,next)
                }
       }
       next();
    }

这样,next函数传递给每个中间函数了,这里的next函数就是下一个要执行函数的包装体

你可能感兴趣的:(Express核心原理)