redux中介軟體的函式簽名形式如下:
() => next => action =>
/*
*/ return (createstore) => (reducer, initialstate, enhancer) =>
chain = middlewares.map(middleware => middleware(middlewareapi))
var dispatch = compose(...chain)(store.dispatch) //compose(f, g, h) 等價於函式
//(...args)=>f(g(h(args)))
return
}
核心邏輯是chain = middlewares.map(middleware => middleware(middlewareapi))和dispatch = compose(…chain)(store.dispatch)這兩行。第1句**是根據中介軟體生成乙個陣列chain,chain的元素是簽名為next => action => 形式的函式,每個元素就是最終中介軟體鏈上的一環。第2句**利用compose函式,將chain中的函式元素組成乙個「洋蔥式」的大函式,chain的每個函式元素相當於一層洋蔥表皮。redux傳送的每乙個action都會由外到內依次經過每一層函式的處理。假設有3層函式,從外到內依次是a,b,c,函式的實際呼叫過程是,a接收到action,在a函式體內會呼叫b(a的引數next,指向的就是b),並把action傳遞給b,然後b呼叫c(b的引數next指向的就是c),同時也把action傳遞給c,c的引數next指向的是原始的store.dispatch,因此是action dispatch的最後一環。這樣分析下來,程式是沒有問題的,但當我們的中介軟體需要直接使用dispatch函式時,問題就出來了。例如,常用於傳送非同步action的中介軟體redux-thunk,就需要在非同步action中使用dispatch:
export function fetchposts(subreddit) .json`)
.then(
response => response.json(),
error => console.log('an error occured.', error)
).then(json =>
dispatch(receiveposts(subreddit, json))
)}}
fetchposts使用的dispatch,是redux-thunk傳遞過來的,指向的是middlewareapi物件中的dispatch,實際等於store.dispatch。當執行dispatch(requestposts(subreddit))時,這個action直接就到了最後一環節的處理,跳過了redux-thunk中介軟體之後的其他中介軟體的處理,顯然是不合適的。我們希望的方式是,這個action依然會從最外層的中介軟體開始,由外到內經過每一層中介軟體的處理。所以,這裡使用的dispatch函式不能等於store.dispatch,應該等於compose(…chain)(store.dispatch),只有這樣,傳送的action才能經過每一層中介軟體的處理。現在問題出來了,chain = middlewares.map(middleware => middleware(middlewareapi))需要使用dispatch = compose(…chain)(store.dispatch)返回的dispatch函式,而dispatch = compose(…chain)(store.dispatch)的執行又依賴於chain = middlewares.map(middleware => middleware(middlewareapi))的執行結果,我們進入死迴圈了。
問題的解決方案就是閉包。當我們定義middlewareapi的dispatch時,不直接把它指向store.dispatch,而是定義乙個新的函式,在函式中引用外部的乙個區域性變數dispatch,這樣就形成了乙個閉包,外部dispatch變數的變化會同步反映到內部函式中。如下所示:
return (createstore) => (reducer, initialstate, enhancer) =>
chain = middlewares.map(middleware => middleware(middlewareapi))
dispatch = compose(...chain)(store.dispatch) //compose(f, g, h) 等價於函式
//(...args)=>f(g(h(args)))
return
} 這樣,「雞生蛋,蛋生雞」的問題就解決了。如果這個例子對你來說太複雜,可以用下面這個簡化的例子幫助你理解:
const middleware = () => (next) => (number) =>
return next(number);
}function test() ;
var middlewareapi =
dispatch = middleware(middlewareapi)(dispatch);
return
}var = test();
dispatch(3);
//輸出:
"in middleware"
"original dispatch"
const middleware = () => (next) => (number) =>
return next(number);
}function test() ;
var middlewareapi =
} dispatch = middleware(middlewareapi)(dispatch);
return
}var = test();
dispatch(3);
//輸出
"in middleware"
"in middleware"
"in middleware"
"in middleware"
"original dispatch"
第二種方式,middleware中dispatch的number會再次經歷中介軟體的處理,當number=3,2,1,0時,都會進入一次middleware函式,當number=0時,next(0)呼叫的是test中定義的初始dispatch函式,因此不再經過middleware的處理。 乙個基於D BUS的中介軟體系統
先來說下什麼是d bus。最便捷的是引用 freedesktop.org的官方英文定義哈,我的初步計畫,基於d bus來實現底層通訊,通過idl介面定義來實現上層業務邏輯的定義,借助idl2dbus生成stub和proxy 從而實現乙個mini版本的中介軟體系統,類似於corba系統,但是足夠輕巧!...
如何設計乙個簡單的訊息中介軟體
我們日常開發當中需要用到訊息中介軟體的場合很多,我們或許也用到了形形色色的訊息中介軟體產品,有老牌的activemq rabbitmq,炙手可熱的kafaka,還有阿里研發的notify metaq rocketmq等等,但反過來思考一下,如果讓我們自己來設計乙個訊息中介軟體,需要考慮哪些方面的問題...
乙個JS菜鳥對閉包的理解
閉包就是能夠讀取其他函式內部變數的函式,在js中,只有函式內部的子函式才能讀取區域性變數,這就造成的一些使用時的不便。而閉包函式的作用就是,像一座橋梁一樣將函式內部和函式外部連線起來。可以保護變數,避免汙染。函式a內部直接或間接返回乙個函式b b函式內部使用函式a內部的私有變數 私有資料 a函式內部...