Express 是一個自身功能極簡,徹底是由路由和中間件構成一個的 web 開發框架:從本質上來講,一個 Express 應用就是在調用各類中間件。javascript
中間件(Middleware) 是一個函數,它能夠訪問請求對象(request object (req
)), 響應對象(response object (res
)), 和 web 應用中處於請求-響應循環流程中的中間件,通常被命名爲 next
的變量。html
若是當前中間件沒有終結請求-響應循環,則必須調用 next()
方法將控制權交給下一個中間件,不然請求就會掛起。java
Koa目前主要分1.x版本和2.x版本,它們最主要的差別就在於中間件的寫法,git
redux的middleware是提供的是位於 action 被髮起以後,到達 reducer 以前的擴展點。github
框架 | 異步方式 |
---|---|
Express | callback |
Koa1 | generator/yield+co |
Koa2 | Async/Await |
Redux | redux-thunk,redux-saga,redux-promise等 |
//Express
var express = require('express')
var app = express()
app.get('/',(req,res)=>{
res.send('Hello Express!')
})
app.listen(3000)
複製代碼
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);
複製代碼
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);
複製代碼
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 }
複製代碼
其實express middleware的原理很簡單,express內部維護一個函數數組,這個函數數組表示在發出響應以前要執行的全部函數,也就是中間件數組,每一次use之後,傳進來的中間件就會推入到數組中,執行完畢後調用next方法執行函數的下一個函數,若是沒用調用,調用就會終止。web
Koa會把多箇中間件推入棧中,與express不一樣,koa的中間件是所謂的洋蔥型模型。express
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
複製代碼
從上圖中得出結論,middleware經過next(action)一層層處理和傳遞action直到redux原生的dispatch。而若是某個middleware使用store.dispatch(action)來分發action,就至關於從新來一遍。redux
在middleware中使用dispatch的場景通常是接受一個定向action,這個action並不但願到達原生的分發action,每每用在一步請求的需求裏,如redux-thunk,就是直接接受dispatch。api
若是一直簡單粗暴調用store.dispatch(action),就會造成無限循環。數組