聊聊方法複合Compose, Redux和Koa中的中間件機制.

簡介.

redux和koa中都支持中間件的機制. 但二者中間件略有不一樣.javascript

  • redux: 中間件的函數都是同步的,挨個遍歷執行便可.
  • koa: 異步的函數,是一個promise,咱們要支持async + await的中間件,因此咱們要等異步結束後,再執行下一個中間件。

同步的方法複合.

我先定義三個簡單的函數, 用來作例子.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的中間件機制.函數

代碼

demo

相關文章
相關標籤/搜索