简介.
redux和koa中都支持中间件的机制. 但两者中间件略有不同.
- redux: 中间件的函数都是同步的,挨个遍历执行即可.
- koa: 异步的函数,是一个promise,我们要支持async + await的中间件,所以我们要等异步结束后,再执行下一个中间件。
同步的方法复合.
我先定义三个简单的函数, 用来做例子.
// 取绝对值.
const abs = val => Math.abs(val);
// +10
const add = val => val + 10;
// 平方
const pow = val => Math.pow(val, 2);
如果我要实现这样的一个功能: 先取绝对值, 再加10,再平方. 调用方式如下:
pow(add(abs(-10)))
// 输出: 400
这种写法, 显然不太合适, 非常的不雅. 而且当函数的个数不定时, 便无法调用了. 正确的姿态是中间件机制. 将所有的中间件复合成一个超级函数. 最后执行这个超级函数即可.
// 合并成一个超级函数.
const composeFn = compose([abs, add, pow]);
// 执行超级函数.
console.log(composeFn(-10));
我们利用Array.reduce方法就很容易实现.
function compose(middlewares) {
if (!middlewares || middlewares.length === 0) {
return val => val;
}
if (middlewares.length === 1) {
return middlewares[0];
}
// 右边的方法包括左边的方法. 最后形成一个超级方法.
return middlewares.reduce((left, right) => {
return (...args) => right(left(...args));
});
}
redux的中间件机制, 正是这种实现.
异步的方法复合.
我先定义三个简单的函数, 用来做例子. 模拟koa的中间件使用.
const p1 = async (ctx, next) => {
ctx.body = '1';
setTimeout(() => {
ctx.body += '2';
}, 2000);
await next();
ctx.body += '3';
};
const p2 = async (ctx, next) => {
ctx.body += '4';
await next();
ctx.body += '5';
};
const p3 = async (ctx, next) => {
ctx.body += '6';
};
每个函数都是一个pormise, 我们要等异步结束后,再执行下一个中间件. 正确的调用姿态是:
setTimeout(async () => {
// 复合成一个超级方法.
const composeFn = compose([p1, p2, p3]);
const ctx = {};
// 执行复合后的方法.
await composeFn(ctx);
// 输出: 146532
console.log(ctx);
});
异步的复合方法合成, 代码如下:
function compose(middlewares) {
// 方法复合, 返回的是一个复合后的方法.
return ctx => {
const dispatch = (i) => {
// 拿出当前要执行的方法.
const current = middlewares[i];
// 定义要执行的下一个方法.
const next = () => dispatch(i + 1);
if (!current) {
return Promise.resolve();
}
// promise完成后,再执行下一个
return Promise.resolve(current(ctx, next));
};
// 执行第0个.
return dispatch(0);
};
}
这正是koa的中间件机制.