逐行解析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函数就是下一个要执行函数的包装体

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值