redux和koa中都支持中間件的機制. 但二者中間件略有不一樣.javascript
我先定義三個簡單的函數, 用來作例子.java
// 取絕對值.
const abs = val => Math.abs(val);
// +10
const add = val => val + 10;
// 平方
const pow = val => Math.pow(val, 2);
複製代碼
若是我要實現這樣的一個功能: 先取絕對值, 再加10,再平方. 調用方式以下:git
pow(add(abs(-10)))
// 輸出: 400
複製代碼
這種寫法, 顯然不太合適, 很是的不雅. 並且當函數的個數不定時, 便沒法調用了. 正確的姿態是中間件機制. 將全部的中間件複合成一個超級函數. 最後執行這個超級函數便可.github
// 合併成一個超級函數.
const composeFn = compose([abs, add, pow]);
// 執行超級函數.
console.log(composeFn(-10));
複製代碼
咱們利用Array.reduce方法就很容易實現.redux
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的中間件機制, 正是這種實現.promise
我先定義三個簡單的函數, 用來作例子. 模擬koa的中間件使用.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);
});
複製代碼
異步的複合方法合成, 代碼以下:async
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的中間件機制.函數