上一篇理解Express的使用之后, 再总结一篇Express中间件的简单实现原理。

我们知道Express中间件就是一个个的函数, 那么怎么让这些函数有序的执行呢? 那就需要我们调用 next 函数。其实 next函数调用的就是下一个中间件函数。

以下代码实现了简单的 app.use 注册中间件, 以及 getpost方式的中间件。其他请求方式的中间件实现同理

核心代码:

const next = () => {
    const stack = stacks.shift()
    if(stack) {
        stack(req, res, next)
    }
}
next()

stacks就是一个数组队列, 存放所有符合规则的中间件函数。遵循先进先出的原则。也就是最先注册的中间件函数最先执行。

实现代码

const http = require('http')
const slice = Array.prototype.slice

 class Express {
     constructor() {
        this.router = {
            all: [], // 匹配所有额中间件函数
            get: [],
            post: []
        }
     }

     /**
      * 这里整合中间件
      * @param {string} path
      * @returns {object}
      */
     middlewareHandler(path) {
        const info = {}
        if (typeof path === 'string') {
            info.path = path
            info.stack = slice.call(arguments, 1)  // 中间件数组
        } else {
            info.path = '/'
            info.stack = slice.call(arguments, 0)
        }

        return info
     }

     use() {
        const allStack = this.middlewareHandler(...arguments)
        this.router.all.push(allStack)
     }

     get() {
        const getStack = this.middlewareHandler(...arguments)
        this.router.get.push(getStack)
     }

     post() {
        const postStack = this.middlewareHandler(...arguments)
        this.router.post.push(postStack)
     }

      /**
       *
       * @param {string} method
       * @param {string} url
       * @returns {Array}
       */
     accordStack(method, url) {
        let stacks = []
        stacks = stacks.concat(this.router.all)
        stacks = stacks.concat(this.router[method])
        return stacks
        .filter(stack => {
            return url.indexOf(stack.path) !== -1
        }).map(item => item.stack[0])
     }

     handler(req, res, stacks) {
         // 函数表达式
        const next = () => {
            const stack = stacks.shift()
            if(stack) {
                stack(req, res, next)
            }
        }
        next()
     }

     callback() {
        return (req, res) => {
            res.json = data => {
                res.setHeader('Content-Type', 'application/json')
                res.end(JSON.stringify(data))
            }

            // 拿到请求的方法和url, 对中间件函数进行筛选
            const {method, url} = req
            const stacks = this.accordStack(method.toLowerCase(), url)
            this.handler(req, res, stacks)
        }
     }

     listen(...args) {
         const server = http.createServer(this.callback())
         server.listen(...args)
     }
 }

 // 工厂模式, 导出一个实例对象
module.exports = () => {
    return new Express()
}

最新文章

  1. sublime text 3 + python配置,完整搭建及常用插件安装
  2. iOS 之消息推送(个推)---个人小结
  3. jquery load 和 iframe 比较
  4. Linux C编程学习之开发工具2---GDB调试器
  5. oracle普通用户登录em
  6. Introduction of Open CASCADE Foundation Classes
  7. Python强化训练笔记(三)——词频的统计
  8. c++11中的for简化用法
  9. magento多语言中文语言包
  10. canvas 绘点图
  11. 敏捷开发的特点(转自MBAlib)
  12. Intent携带额外的数据的方法
  13. android sdk 深入理解adb
  14. Linux - 在Ubuntu下永久修改主机名
  15. 【转】HTML CANVAS
  16. js来判断设备类型
  17. Vue混入
  18. Centos7 安装配置mysql5.6
  19. Django 跨域请求
  20. c# 后台post,包含file文件

热门文章

  1. Proxy opening connection toSpringClound配置豪猪hystrixDashboard发生
  2. K 大神的博弈知识汇总
  3. python入门之paramiko模块
  4. 类成员函数的重载、覆盖和隐藏区别 (C++)(转)
  5. mysql服务器查询慢原因分析方法
  6. .net 中的托管与非托管
  7. Oracle同义词。。。
  8. hibernate课程 初探单表映射1-9 创建关系映射文件
  9. NOIP2013Day1T3 表示只能过一个点
  10. npm warn weex @1.0.0 no repository field