// 用法var express = require("express")var app = express()app.use((req, res, next) => { next()})app.get("/", function(req, res) { res.send("Hello world!")})app.listen(3000)//************************************************ */// 中间件实现原理function use(route, fn) { var handle = fn var path = route // 不传入route则默认为'/',这种基本是框架处理参数的一种套路 if (typeof route !== "string") { handle = route path = "/" } // 存储中间件,与koa不同,这里会存储路由与函数的映射关系 this.stack.push({ route: path, handle: handle }) // 以便链式调用 return this}// 函数自身内部维护自增标识符,next函数,调用next函数,消费队列,把next函数传递给function handle(req, res, out) { let index = 0 function next(err) { // 依次取出中间件 const { router, handle } = stack[index++] // 终止条件 if (!stack[index++]) { defer(done, err) return } // 路由匹配规则,如果不匹配,跳过当前中间件执行 if (router !== path) { return next(err) } // 执行中间件,传递错误,与上下文对象,next函数 call(layer.handle, route, err, req, res, next) } next()}function call(handle, route, err, req, res, next) { if (err && handle.length === 4) { // 错误处理中间件 handle(err, req, res, next) return } else if (!err) { // 请求处理中间件 handle(req, res, next) return }}
connect 中间件与 koa 中间件差异
- connect中提供路由匹配的功能,Koa中间件的执行并不需要匹配路由,所以注册的中间件每一次请求都会执行
- connect在捕获中间件的异常时,通过next携带error一个个中间件验证,直到错误处理中间件,而Koa中则是用Promise包装中间件,一旦中间件发生异常,那么会直接触发reject状态,直接在Promise的catch中处理就行
- Koa中通过继承event,暴露error事件让开发者自定义异常处理
- Koa中res.end由中间件执行完成之后自动调用,这样避免在connect忘记调用res.end导致用户得不到任何反馈
- Koa中采用了async/await语法让开发者利用同步的方式编写异步代码