Express, Koa, Redux中介軟體的區別,寫法和執行流程

丁巨集宇發表於2018-07-29

1. 區別

Express

Express 是一個自身功能極簡,完全是由路由和中介軟體構成一個的 web 開發框架:從本質上來說,一個 Express 應用就是在呼叫各種中介軟體。

中介軟體(Middleware) 是一個函式,它可以訪問請求物件(request object (req)), 響應物件(response object (res)), 和 web 應用中處於請求-響應迴圈流程中的中介軟體,一般被命名為 next 的變數。

如果當前中介軟體沒有終結請求-響應迴圈,則必須呼叫 next() 方法將控制權交給下一個中介軟體,否則請求就會掛起。

Koa

Koa目前主要分1.x版本和2.x版本,它們最主要的差異就在於中介軟體的寫法,

Redux

redux的middleware是提供的是位於 action 被髮起之後,到達 reducer 之前的擴充套件點

對比

框架 非同步方式
Express callback
Koa1 generator/yield+co
Koa2 Async/Await
Redux redux-thunk,redux-saga,redux-promise等

2. 寫法

Express

//Express
var express = require('express')
var app = express()
app.get('/',(req,res)=>{
    res.send('Hello Express!')
})
app.listen(3000)
複製程式碼

Koa1

var koa = require('koa');
var app = koa();

// logger

app.use(function *(next){
  var start = new Date;
  yield next;
  var ms = new Date - start;
  console.log('%s %s - %s', this.method, this.url, ms);
});

// response

app.use(function *(){
  this.body = 'Hello World';
});

app.listen(3000);
複製程式碼

Koa2

const Koa = require('koa');
const app = new Koa();

// logger
// common function 最常見的,也稱modern middleware
app.use((ctx, next) => {
  const start = new Date();
  return next().then(() => {
    const ms = new Date() - start;
    console.log(`${ctx.method} ${ctx.url} - ${ms}ms`);
  });
});

// logger
// generatorFunction 生成器函式,就是yield *那個
app.use(co.wrap(function *(ctx, next) {
  const start = new Date();
  yield next();
  const ms = new Date() - start;
  console.log(`${ctx.method} ${ctx.url} - ${ms}ms`);
}));

// logger
// async function 最潮的es7 stage-3特性 async 函式,非同步終極大殺器
app.use(async (ctx, next) => {
  const start = new Date();
  await next();
  const ms = new Date() - start;
  console.log(`${ctx.method} ${ctx.url} - ${ms}ms`);
});

// response
app.use(ctx => {
  ctx.body = 'Hello Koa';
});

app.listen(3000);
複製程式碼

Redux

import { createStore, applyMiddleware } from 'redux'
/** 定義初始 state**/
const initState = {
  score : 0.5
}
/** 定義 reducer**/
const reducer = (state, action) => {
  switch (action.type) {
    case 'CHANGE_SCORE':
      return { ...state, score:action.score }
    default:
      break
  }
}

/** 定義中介軟體 **/
const logger = ({ dispatch, getState }) => next => action => {
  console.log('【logger】即將執行:', action)

  // 呼叫 middleware 鏈中下一個 middleware 的 dispatch。
  let returnValue = next(action)

  console.log('【logger】執行完成後 state:', getState())
  return returnValue
}

/** 建立 store**/
let store = createStore(reducer, initState, applyMiddleware(logger))

/** 現在嘗試傳送一個 action**/
store.dispatch({
  type: 'CHANGE_SCORE',
  score: 0.8
})
/** 列印:**/
// 【logger】即將執行: { type: 'CHANGE_SCORE', score: 0.8 }
// 【logger】執行完成後 state: { score: 0.8 }

複製程式碼

3. 執行流程

Express

其實express middleware的原理很簡單,express內部維護一個函式陣列,這個函式陣列表示在發出響應之前要執行的所有函式,也就是中介軟體陣列,每一次use以後,傳進來的中介軟體就會推入到陣列中,執行完畢後呼叫next方法執行函式的下一個函式,如果沒用呼叫,呼叫就會終止。

express的請求

Koa

Koa會把多箇中介軟體推入棧中,與express不同,koa的中介軟體是所謂的洋蔥型模型。

Koa中介軟體原理

var koa = require('koa');
var app = koa();

app.use(function*(next) {
  console.log('begin middleware 1');
  yield next;
  console.log('end middleware 1');
});

app.use(function*(next) {
  console.log('begin middleware 2');
  yield next;
  console.log('end middleware 2');
});

app.use(function*() {
  console.log('middleware 3');
});

app.listen(3000);

// 輸出
begin middleware 1
begin middleware 2
middleware 3
end middleware 2
end middleware 1
複製程式碼

Redux

dispatch流程

從上圖中得出結論,middleware通過next(action)一層層處理和傳遞action直到redux原生的dispatch。而如果某個middleware使用store.dispatch(action)來分發action,就相當於重新來一遍。

在middleware中使用dispatch的場景一般是接受一個定向action,這個action並不希望到達原生的分發action,往往用在一步請求的需求裡,如redux-thunk,就是直接接受dispatch。

如果一直簡單粗暴呼叫store.dispatch(action),就會形成無限迴圈。

參考文章

Redux,Koa,Express之middleware機制對比

koa,redux等主流框架的中介軟體設計思想原理分析

Koa入門, 中介軟體介紹

理解 Koa 的中介軟體機制

Redux, Middleware

相關文章