解讀:Flux 是什麼?
引言:本文的目標是通過了解Flux 提出的模式,來明白Flux 的核心要點,以及弄清楚它到底是什麼。並且,由於Flux不是傳統意義上的軟體包,因此我們將仔細研究通過Flux 來解決設計思路上的問題。
本文選自《Flux架構》。
Flux 作為一種全新的方式,用於支持建立複雜的可擴展用戶界面。當你在網上搜尋Flux的相關資料時,能了解到的大概也就是類似以上這些內容了。但我們該如何定義這樣一種全新的方式呢?又是什麼讓其優於其他前端架構呢?
Flux 是一套模式
我們可能首先會在理解上遇到嚴酷的現實——Flux 並非軟體包;其實,它是一套方便我們去遵循的架構模式。這聽起來似乎令人失望,不過別難過,有很好的理由不將其作為一個框架來實現。相比實際實現,在貫穿本書的內容中,我們將會看到Flux 作為一套模式而存在的價值。現在,讓我們開始了解Flux 中的一些上層架構模式吧。
1 . 數據入口
在傳統前端架構設計中,我們很少考慮如何處理系統的數據入口。我們可能對此有個初步的方案,但是並不具體。例如,通過MVC(模型-視圖-控制器)架構,讓控制器來控制數據流。通常,這很有用。但另一方面,控制器實際控制的只是當數據已經存在後所發生的事情。那麼控制器該如何在一開始就獲取數據呢?如下圖所示。
初看此圖,似乎沒什麼問題。以箭頭標識的數據流應該很容易跟蹤。但數據從哪裡來的呢?例如,通過用戶事件,視圖可以創建新的數據,並傳遞給控制器;根據各控制器之間的層次關係,一個控制器可以產生新數據並傳遞給另一個控制器。但關於控制器,它能自己創建數據給自己使用嗎?
在類似這樣的圖中,這些問題看起來並不重要。但是,如果我們嘗試將它擴展到擁有數百個類似組件後,數據入口在這個系統中的地位就非常重要了。因為Flux 是一種用於複雜系統的可擴展架構,所以在這種架構模式下,數據入口是十分重要的。
2 . 狀態管理
狀態是我們在前端開發中經常需要處理的。不幸的是,我們難以在無任何副作用的情況下整合所有的純函數,這有兩個原因:第一,我們的代碼需要與DOM 有正向或反向的交互,這也是用戶在界面中所能感知到的;第二,我們不能把程序里所有的數據都存在DOM中(至少現在不能),這些數據會因為時間的推移和用戶的操作而發生變化。
在Web 應用中,並沒有現存的狀態管理的方法,但有多種方式來限制狀態改變的數量,以及規定如何發生改變。例如,純函數不能修改任何狀態,它們只能創建新數據。以下是 一個類似的示例。
正如你所看到的,此處的純函數並沒有副作用,因為,任何對它們的調用,都不會導致狀態的變化。如果狀態的改變是不可避免的,那麼為什麼還要採用這種做法?我們的方法是規定狀態在哪裡改變。例如,如果只允許部分組件類型可以修改程序里的數據狀態,這樣,我們就可以掌控哪些源可以引起狀態變化。
Flux 十分擅長控制狀態在哪裡發生改變。在後面部分,我們會看到Flux 存儲器(Stores)如何管理這些狀態的改變。Flux 如何管理狀態的重要性所在,是它在架構層上的處理。設計一套規則來決定哪些組件類型可以變更程序數據,這讓我們感到很困擾,而相對於此,通過Flux 則不需要花費什麼精力來考慮在哪裡更改狀態。
3 . 保持同步更新
數據入口點是同步更新的重要概念。也就是說,除了管理該狀態變化的來源,我們還必須要管理這些相對於其他事務的變化順序。如果數據入口點就是我們的數據,這時候我們應該同步地將狀態的改變應用到系統中的所有數據。
讓我們花點時間想想這為什麼如此重要。在系統中數據被非同步更新時,我們必須考慮競爭條件。競爭條件可能會產生問題,因為一個數據可能依賴於另一個,如果它們以錯誤的順序更新,我們會遇到一連串的問題。下圖說明了這個問題。
當事務是非同步的時,我們無法控制何時發生狀態改變。因此,我們所能做的就是等待非同步更新發生,然後檢查數據,並確保滿足所有的數據依賴。沒有自動化工具為我們處理這些依賴,我們只能寫很多代碼來檢查狀態。
Flux 通過確保同步更新數據存儲器解決了這個問題。這意味著,上圖所示的情況不會發生。下圖更好地展示了Flux 是如何處理當今典型的JavaScript 應用程序中的數據同步問題的。
4 . 信息架構
我們常常忘記自己置身於IT 行業,應該圍繞信息發展技術。然而近期,風向大變,在新形勢下,我們在探討信息之前被迫考慮實現。通常,應用中所用的數據源暴露出的數據,並不是用戶想要的。我們需要JavaScript 將這些原始的數據變成用戶可接受的數據。這就是我們的信息架構。
這是否意味著Flux 被用於設計信息架構,而不是軟體架構?並非如此。實際上,Flux組件被實現為真實軟體的組件,用於執行實際計算。訣竅是,Flux 模式使我們可以將信息架構作為首要的設計考量。不是非得通過各種組件及其實現問題來進行篩選,而是我們可以確保得到正確的信息給用戶。
一旦我們的信息架構初具規模,更大的應用程序就會接踵而至,作為一種我們試圖傳達給用戶信息的自然擴展。從數據中產生信息是困難的部分。我們不僅僅需要從大量的數據源中提取信息,並且這些信息也必須對用戶產生價值。在任何項目中犯這種錯誤都將面臨巨大風險。當處理正確時,我們就可以繼續處理特定的應用程序組件,如按鈕控制項的狀態等。
Flux 架構保持數據在存儲器中進行轉換。存儲器是一個信息工廠,原始的數據進入,新的信息產出。存儲器控制數據如何進入系統、同步狀態變化、定義狀態如何變化。當我們深入了解存儲器後,將看到它們如何成為信息架構的支柱。
Flux 並不是一個框架
現在,我們已經對Flux 的上層模式進行了一定的探索,讓我們再來想一下:什麼是Flux?其實,它只是一組可以應用到前端JavaScript 程序中的架構模式。因為Flux 將信息放在首位,從而使其具有良好的擴展性。信息是軟體中很難擴展的一部分,而Flux 推進了對信息架構的處理。
那麼,為什麼不將Flux 模式實現為一個框架呢?如果這樣的話,Flux 需要提供一個標準實現給大家使用,像其他的大型可擴展開源項目一樣,其代碼也需要隨著項目的發展而不斷更新。
現在主要的問題是,Flux 是在架構層上運行的,它用於解決阻礙已有程序擴展的信息問題,以滿足用戶需求。如果Facebook 決定以一個框架的形式去發布Flux,那麼就會遇到類似其他框架發展的困擾。例如,一些框架的組件不能在工作中以最適合的方式實現,如果不侵入框架,那就很難去實現一個更好的方案。
Facebook 決定放棄實現完整的Flux 是多麼棒啊!他們確實提供了少量的Flux 組件實現,但僅供參考。這些實現是有用的,但主要用來作為我們理解運作機制的起點,例如分發器如何像預期那樣工作。我們可以隨意以我們了解的相同的Flux 架構模式來進行實現。
Flux 並不是一個框架,這是否意味著我們需要去自行實現Flux?不,不需要。實際上,開發者正在實現Flux 庫,並將它們開源。一些Flux 庫很貼近Flux 的架構模式;另一些Flux實現庫有自己獨到的理解,使用它們並不會有錯,只要合適就行。Flux 模式旨在基於JavaScript 開發解決通用概念問題,因此在深入探討Flux 實現之前要掌握其定義。
Flux 的設計思路問題解決方案
如果Flux 只是架構模式的集合,而不是一個軟體框架,那麼它能解決什麼樣的問題呢?我們將從架構角度來看Flux 所能解決的設計思路問題,包括:單向數據流、可追溯性、一致性、組件分層和低耦合組件。這些問題都會在我們的軟體中產生風險,尤其是大型可擴展應用。Flux 可幫助我們擺脫這些問題。
1 . 數據流向
我們正在建立一個信息架構,使得具有複雜功能的應用能夠在此之上構建。數據流入系統,並最終到達終點,從而結束整個流程。在入口點和終止點之間所發生的就決定了Flux架構的數據流,如下圖所示。
數據流的概念是一個很好的抽象,因為這可以很好地去可視化數據的流向,你可以很清楚地描述它如何進入系統,然後從一個點移動到另一個點,最終流動停止。但在它之前,會有些副作用發生,那就是上圖的中間塊所關心的問題,因為我們不能確切地知道這個數據流是如何到達終點的。
比方說,我們的架構並不對數據流有任何限制。任何組件都允許將數據傳遞給其他組件,無論組件的層次在哪裡。請看下圖。
正如你所見,我們的系統已經很明確地定義了數據的入口和出口。這太棒了,因為這意味著我們可以很自信地說出流經系統的數據流。但問題是,系統中各組件之間的數據流並沒有在這張圖中展現。圖中數據流是沒有方向可循的,更確切地說,是多方向的,這糟糕透了。
Flux 是一個單向數據流架構。這意味著,上圖中的組件層是不可能出現的。現在的問題是,為什麼說多向數據流不好?有時候,我們會覺得數據在各組件之間以任意方向傳遞
是很方便的,這並不是個問題,因為傳遞數據不會破壞我們的架構。然而,當數據在系統中的移動是多方向的時,我們需要花更多的精力去為它們同步。簡單來說,如果數據沒有按照一致的方向進行流動,就有出錯的可能。
Flux 強制數據流的方向,因而降低了因組件更新順序不當而破壞系統的可能性。無論什麼數據進入系統,都應當按照同樣的順序流入系統,如下圖所示。
2 . 可回溯性
我們知道,當數據流單向地從系統進入組件中的時候,很容易預測和跟蹤所有可能會產生的影響。相反,當一個組件向其他任何一個組件發送數據的時候,卻很難捕捉到數據是如何到達的。為什麼會這樣?通過調試器,我們現在很容易地可以在運行時遍歷任何一級,無論有多複雜。但這個概念的問題在於,我們只是調試我們所需要的。
Flux 架構中的數據流本質上是可預測的。這對於許多活動設計都是十分重要的,而不只是局限於調試。所以在用了Flux 架構的應用中,程序開發者能很直觀地知道即將發生什麼。這種預期是很關鍵的,因為這樣可避免讓我們設計出死胡同一樣的程序。當我們能夠很容易地弄清楚因果時,就可以將大部分時間花在構建應用的功能上,因為這才是用戶真正關心的。
3 . 通知的一致性
在Flux 應用中,我們從一個組件向另一個組件發送數據時,需要保持數據流向的一致性。在保持一致的時候,還需要考慮系統中的數據流向機制。
例如,分發和訂閱就是一個在組件間通信十分流行的機制。這種方法所帶來的好處就是,我們的組件可以相互通信,並且保持一定程度上的解耦。事實上,這在前端開發中是相當普遍的,因為組件的通信都是由用戶的事件所驅動的。這些事件可以被認為是「即發即棄」的。任何其他組件想在某種方式上響應這些事件,都需要去訂閱這個特定的事件。
分發和訂閱的機制雖然有它的優點,但它在架構上也遇到了挑戰,尤其是在大型複雜的應用中。例如,為了開發某項新功能,我們增加了幾個新組件,但是以下這幾點一直會困擾著我們:這些組件應該接受來自已有組件的消息更新嗎?它們會得到這些更新響應的通知嗎?它們應該先響應嗎?這就是複雜性所帶來的數據依賴問題。
分發和訂閱帶來的另一個挑戰就是,我們有時需要先訂閱一個通知,而後取消該訂閱。這樣,當我們試圖在擁有眾多組件的系統中,去嘗試保持組件完整的生命周期,不僅十分困難,而且會增加丟失事件捕獲的幾率,從而破壞了一致性。
Flux 方法,則是通過維持一個靜態的內部組件信息樹,來規避上面的問題,從而將消息分發到每個組件中去。換句話說,程序開發者並不需要去挑選組件所需要訂閱的事件,而只需要區分出分發給它們的事件中哪些是相關的,剩下的則可以忽略。下面是關於Flux如何分發消息的示意圖。
Flux 分發器給每個組件發送事件,沒有其他機制可以繞過這種方式。我們需要實現組件內的邏輯來判斷此消息是否有用,以取代對消息結構的篡改而導致的難以擴展的問題。並在組件內部來聲明對其他組件的依賴,這樣對接下來的數據流向很有幫助。
4 . 簡捷的架構分層
分層是一種對組件進行組織的很好的架構方式。一方面是因為分層能夠對應用的各種模塊進行明確的分類,另一方面是因為分層可以對通信路徑做出限制。後一點與Flux 架構尤其相關,因為保持其數據流的單向性是十分重要的,而對分層做限制比對獨立組件做限制要容易得多。下面所示的是Flux 分層的示意圖。
上圖主要描繪了數據在三個分層之間是如何流動的。(微信後台回復「Flux 組件」,我們將會對Flux 組件的類型進行引導性解釋。)
從上圖中可以看到,數據從一個分層流向下一個分層,並且保持同一個方向。Flux 僅有幾層,應用的規模以組件數量來衡量,而分層的數量仍然是固定的。當給一個已經很龐大的應用增添新特性時,會使其複雜度達到上限。所以,除了限制分層數量和數據流方向,Flux 架構也限制了哪些分層可以與其他分層進行通信。
例如,動作層(Action Layer)可以與視圖層(View Layer)進行通信,並且該通信是單向的。我們可以編寫Flux 設計的分層,並且不允許跳過某個分層。確保一個分層只能與位於其下緊鄰的分層進行通信,可以避免無序引入的代碼問題。
5 . 低耦合渲染
Flux 設計的一個亮點在於架構不用關心UI 元素如何被渲染,也就是說,視圖層與架構的其他部分是低耦合的。這樣設計是有原因的。
Flux 首先是一個信息架構,其次才是一個軟體架構。我們將首先學習其作為信息架構的思想,最後會學習其作為軟體架構的思想。我們知道,視圖技術的缺點是它會對架構的其他部分產生副作用,例如一個和DOM 進行特殊交互的視圖就會產生這樣的影響,所以,一旦我們決定使用這項技術,它勢必會對信息架構的組織方式產生影響。這並不一定是件壞事,但它將導致我們對最終呈現給用戶的信息做出妥協。
實際上,我們真正應該思考的是信息本身,以及信息是如何變化的。哪些相關行為會導致這些變化?數據之間是如何依賴的?Flux 不受當下瀏覽器技術的限制,這使得我們可以優先關注信息本身。因此,在信息架構中插入視圖使其變為軟體產品是很容易的。
本文選自《Flux架構》
※我們採訪了美柚VP,聽聽他怎麼使用阿里視頻雲和CDN
※分布式服務Dubbo從入門到「精通」之Schema實現
※實施計劃:我們是怎麼做采雲間DPC遷移方案的?
※阿里人工智慧實驗室王剛:找到合適的應用場景是實現人工智慧商業化的關鍵點
※淺談Greenplum的Boolean類型與Text類型之間的轉換
TAG:雲棲社區 |
※miru tights7話解讀 觀眾:這誰能學得下去啊
※「剖開」 LinuxONE和Exadata,架構專家解讀裡面到底有什麼
※「剖開」 LinuxONE 和 Exadata,架構專家解讀裡面到底有什麼
※Elon Musk財報金句解讀:特斯拉的未來在哪裡?
※新手必讀系列:實例解讀TensorFlow
※fate/extra6集解讀:看不懂也沒事 看尼祿和愛麗絲賣萌就夠了
※哈佛醫學院解讀AlphaFold:有進步,未解決根本問題
※disruptor 源碼解讀
※親子閱讀/英語啟蒙:The Very Lonely Firefly解讀
※官方解讀:TensorFlow 2.0 新的功能特性
※經典解讀!eos.io上FAQ第21問的中文翻譯和解讀
※解讀Facebook加密穩定幣Libra,看這一篇就夠了
※解讀 | 為什麼蘋果 Mac Pro 只能在中國組裝?
※iPhone為什麼賣這麼貴?三方面解讀iPhone定價背後的原因
※Deep Forest 演算法解讀
※哈佛醫學院研究員解讀DeepMind大突破AlphaFold:有進步,但未解決根本問題
※i8繼任者?關於寶馬BMW Vision M Next最詳細的解讀在這裡
※官方解讀:TensorFlow 2.0中即將到來的所有新特性
※EVA解讀:Seele標誌的背面你見過嗎?
※【大牌解讀】鑽石之王Harry Winston 到底吸引了多少位時尚Icon?