Facebook的Flux和React.js剛剛變得很火,大有剿滅MVC之勢,如今又有人提出再見Flux,新的Bacon/Rx有哪些優點呢?
Facebook一年前引入Flux架構,它是客戶端創建Web應用的最新革新,是對Angular.js的前端MVC的提高與革命,現在已經成爲Web開發者最火熱的技術。
Flux是使用dispathcer將業務邏輯從用戶界面中分離出來,核心思想是單向數據流,這意味着響應用戶動做的事件的傳播能夠單向傳遍整個系統,不須要綁定任何內部數據模型:前端
這種單向數據流與React的虛擬DOM綁定,使得Flux實現更加簡潔,由於沒有必要進行狀態區分(虛擬DOM框架實現這個一功能),可是Flux是重量的,它引入了多個模板(如 事件發射器、監聽器等等),有一些企業軟件的繁瑣酸味,如按約定編程與分層結構。
函數響應式編程Functional Reactive Programming (FRP) 是一種新的編程範式,事件建模爲事件流,事件流是相似一個不變的數組,它們可以被map 過濾 combine和merge,數組和事件流的區別是事件流中的事件是異步的,每次當事件發生時,它會被經過流傳播,最終被訂閱者消費使用。
顧名思義,Reactive響應式編程是React的本質,發生的動做經過事件流傳播,這些事件流結合起來造成應用的狀態,當事件經過系統傳播之後,新的應用狀態對象致使了狀態的訂閱者,它會經過根級別的React組件從新渲染:
整個狀態廣播的邏輯能使用下面代碼實現,使用的是Bacon.js做爲FRP庫:react
// app.js
const React = require('react'),
Bacon = require('baconjs'),
TodoApp = require('./todoApp'),
todos = require('./todos'),
filter = require('./filter')
const filterP = filter.toProperty(<initial filter>),
itemsP = todos.toItemsProperty(<initial items>, filterP)
const appState = Bacon.combineTemplate({
items: itemsP,
filter: filterP
})
相比Flux,這樣作的好處是再也不須要分離動做和存儲,事件流很是簡單,取而代之是一個業務組件,它有一個公共API經過本地dispatcher與業務邏輯進行通信:git
// todos.js
const Bacon = require('baconjs'),
Dispatcher = require('./dispatcher')
const d = new Dispatcher()
module.exports = {
toItemsProperty: function(initialItems, filterP) {
// "business logic"
const itemsP = Bacon.update(initialItems,
[d.stream('remove')], removeItem,
[d.stream('create')], createItem,
...
)
return Bacon
.combineAsArray([itemsP, filterP])
.map(setItemsDisplayStatusBasedOnFilter)
function createItem(items, newItemTitle) {
return items.concat([{<new item data>}])
}
function removeItem(items, itemIdToRemove) {
return items.filter(it => it.id !== itemIdToRemove)
}
...
},
// "public API"
createItem: function(title) {
d.push('create', title)
},
removeItem: function(itemId) {
d.push('remove', itemId)
},
...
}
dispatcher.js是一個可發佈的事件流,事件流可以被訂閱和消費:程序員
// dispatcher.js |
視圖代碼以下,視圖會變得簡單,沒有回調,監聽者,React的虛擬DOM會作剩餘的工做,咱們只要同步公共API去調用業務邏輯:github
// todoItem.jsx
const React = require('react'),
todos = require('./todos')
module.exports = React.createClass({
render: function() {
const item = this.props.item
return (
<li className={item.states.join(' ')}>
<div className="view">
<label>{item.name}</label>
...
<button
className="destroy"
onClick={() => todos.removeItem(item.id)}
/>
</div>
</li>
)
}
})
以上代碼演示見:TodoMVC project
Good bye Flux, welcome Bacon/Rx? — Medium
點評:Bacon/Rx的事件流相似事件總線,雖然很簡單,可是理解起來有必定難度,而Flux雖然繁瑣一些,可是一板一眼,對於前端程序員比較容易理解。
編程