中间件的实现原理

来源:互联网 发布:安卓网络配置文件路径 编辑:程序博客网 时间:2024/06/05 14:09

           用过express的同学都知道,一个HTTP请求的完成就是经过若干中间件完成的,中间件是一个可访问请求对象(req)和响应对象(res)的函数,在 Express 应用的请求-响应循环里,下一个内联的中间件通常用变量 next 表示。

       那么现在我先上一道我面试中遇到的一道题,考的就是中间件的一个实现思路。当然如果你知道express,会更好地帮助你理解。

       

     function fun1(ctx, next) {         ctx.count++;         console.log(ctx.count);         next();     }     function fun2(ctx, next) {         ctx.count++;         console.log(ctx.count);         next();     }     function  fun3(ctx, next) {         ctx.count++;         console.log(ctx.count);         next();     }     compose([fun1, fun2, fun3])({count: 1});
      

这道题的是让你实现一个compose,使得compose([fun1, fun2, fun3])({count: 1})调用后,使得fun1 fun2 fun3依次执行,比如在fun1里面当
next被调用时,就会把控制权交给下一个中间件函数,fun1的下一个中间件函数fun2就会被执行,{count:1}是传入的context,中间件函数就是
依次对context对象进行处理。

     我的compose实现思路很简单,如下

 function compose(arr){         index = 0;         len = arr.length;         return function (ctx) {             function next() {                 index++;                 if(index >= len) return;                 arr[index](ctx, next);             }             arr[index](ctx, next);         }     }

这样输出的结果是 2 3 4,和预期相符

下面我们来验证一个这个解法对不对。

测试一:如果在某个中间函数体中,用户没有调用next,则不会继续调用下个中间件函数。

function fun1(ctx, next) {         ctx.count++;         console.log(ctx.count);         next();     }     function fun2(ctx, next) {         ctx.count++;         console.log(ctx.count);//         next();                }     function  fun3(ctx, next) {         ctx.count++;         console.log(ctx.count);         next();     }     compose([fun1, fun2, fun3])({count: 1});
如上在fun2中没用调用next ,则输出为2 3,和预期相符

测试二:如果next的调用在异步环境里面,则下一个中间件函数必须等上一个中间件函数的next真正被调用(即使是异步)时才会执行。

function fun1(ctx, next) {         ctx.count++;         console.log(ctx.count);         next();     }     function fun2(ctx, next) {         ctx.count++;         console.log(ctx.count);         setTimeout(function () {             next();         },1000);     }     function  fun3(ctx, next) {         ctx.count++;         console.log(ctx.count);         next();     }     compose([fun1, fun2, fun3])({count: 1});
如上,在fun2中1s后才调用next,输出为 2 3 然后一秒后输出4 ,符合预期。

当然这是一个最简单的中间件实现思路,在express中间件中远比这复杂,但是这可以考察你解决问题的思路。