示例代码托管在: http://www.github.com/dashnowords/blogs
博客园地址:《大史住在大前端》原创博文目录
华为云社区地址:[你要的前端打怪升级指南]
在中间件系统的实现上, KOA 中间件通过 async/await 来在不同中间件之间交换控制权, 工作机制和栈结构非常相似, 建议结合《express 中间件系统的基本实现》对比学习, 两个框架所基于的语法特性有区别 (express 使用 ES5 的回调风格语法, KOA 使用 ES7 的扁平式异步 async/await 风格语法), 但在框架基本原理上是很类似的, 只是中间件写法和遍历机制稍有不同.
一. API 层
初始化方法
let middleware = new MiddleWare();
添加中间件函数的方法
- //Fn 为被添加的中间件, KOA 中间件为 async 函数
- middleware.use(Fn);
预处理中间件栈
- // 将存储于数组中的各个中间件组合为按照 "先进后出" 原则执行的中间件系统.
- middleware.start = middleware.compose();
启动中间件队列
middleware.start(ctx);
二. 核心类的定义
- /*
- * KOA 中间件框架的基本实现
- */
- class MiddleWare {
- constructor(){
- this.queue = []
- }
- // 添加中间件函数
- use(fn){
- this.queue.push(fn);
- }
- // 合并中间件处理流, 是一个高阶函数, 调用一次后会生成真正需要的函数.
- compose(){
- return function (ctx, next) {
- let _this= this;
- let index = -1;
- return dispatch(0);
- /**
- * KOA 中间件的工作的步进函数
- */
- function dispatch(i) {
- index = i;
- // 依次取用数组中添加的中间件函数
- let fn = i === _this.queue.length ? next : _this.queue[i];
- if(!fn){
- return Promise.resolve();
- }
- try{
- /*
- * 中间件函数的形式为 async fn(ctx, next), 可以看到此处透传了 ctx 的引用,
- * 同时 next 是一个延迟执行中间件队列中下一个中间件的函数, 也就是说如果在前
- * 一个中间件的函数体中调用 await next(), 就会启动下一个中间件, 实际执行
- * 的函数是 dispatch(i+1).
- */
- return Promise.resolve(fn(ctx,()=>{
- return dispatch(i+1);
- }));
- }catch(err){
- return Promise.reject(err);
- }
- }
- }
- }
- }
三. 使用 use 方法添加中间件
- // 添加回调函数
- middleware.use(async function(ctx, next){
- console.log('step 001');
- ctx.info = 'go through middleware1';
- await next();
- console.log('step 006');
- });
- middleware.use(async function(ctx, next){
- console.log('step 002');
- await next();
- console.log('step 005');
- });
- middleware.use(async function(ctx, next){
- console.log('step 003');
- await next();
- console.log('step 004');
- });
四. 中间件实例
- // 初始化
- let middleware = new MiddleWare();
- /*
- ... 此处为添加中间件的代码
- */
- middleware.start = middleware.compose();
五. 查看运行结果
可以看到有错误发生和正常响应时的不同结果:
六. 在服务器端运行
用 node 起一个 web 服务器那真是太随意了~
- // 启动 http 服务
- http.createServer(function(req, res){
- console.log(req.url);
- let info = {};
- middleware.start(info);
- res.end(JSON.stringify(info));
- }).listen(9527);
看一下效果 (访问服务器时自定义消息就可以传至前台了):
来源: https://www.cnblogs.com/dashnowords/p/10439605.html