本文是 狀態管理框架 選型預研時看到油管上一個Talk的部份內容的總結和一些本身的思考。程序員
要引入一個框架,從上到下的過程包括數據庫
狀態管理框架 可追根溯源到函數式的本質特性上,因此有必要先搞清楚函數式爲什麼物。編程
而一個「新」事物的流行每每會產生泡沫,因此也會有人把函數式當成 銀彈 ,如同對待 區塊鏈 ,人工智能 和 大數據 同樣。在這裏但願一方面把函數式的前因後果說清,另外一方面戳破這些浮誇的 泡沫效應 ,讓它迴歸到原有的價值。swift
函數式的歷史能夠追述到1930年代的{lambda calculus},函數式編程本質上就是對 λ演算 的一種實現。基本思想就是只經過「變量」和「函數」兩個元素來解決問題。這個思想給函數式編程帶來諸如 匿名函數 、 一等公民 、 柯里化 等概念。數組
咱們所接觸到的主流編程語言幾乎都是 圖靈機 的思想延續,可見這一分支一直是處於絕對統治地位。但隨着現代語言愈來愈多的加入 λ演算 的特性,這兩個思想最終產生了交集。安全
那麼函數式思想爲何從一個小衆的事物慢慢變成了顯學了呢?那麼咱們看一下這個思想到底給軟件工程注入了哪些新鮮血液。網絡
有一種誤解是學習函數式要忘記掉你所學過的編程方式,但與其說引入函數式就是要用它替代 面向對象 ,還不如說是對 面向對象 的程序進行重構,畢竟二者各有優劣。閉包
咱們一開始知足某個業務寫的 面向對象 代碼多是如下的樣子,你能夠把他看作一些頁面,函數或是模塊。併發
隨時業務的變化,可能有些組件被刪掉,或是新增了新的模塊,也多是模塊間的調用/依賴關係有了變化。因而複雜度開始增大。app
代碼變成這個樣子後,雖然表面上仍然可使用,可是源碼卻已經難以理解和維護 咱們會發現難以理解的一個緣由是:這個系統一件事的成立,須要大量的前提! ++由於依賴太多++
圖靈系的語言也有同樣的困境,隨着語言的迭代更新,逐漸加入了更多的限制:
當一個概念愈來愈難以理解的時候,就到了一個改變的節點上。好比減小概念:Swift就沒有protect關鍵字 why;但更有效的思路是引入更加簡單的 函數式 。
數學家,和程序員同樣,對概念的 封裝 , 組合 有着巨大的需求。 例如英國數學家在一本著做中花了379頁推導出1+1=2
他們是怎麼管理好這麼多封裝,最終能串聯起來解決問題的呢? 能否把他們的經驗拿來借鑑?
答案就是 數學函數
數學函數 是輸入集合到輸出集合映射。
而函數式語言的函數特性就是 數學函數
這和 面向對象 的函數可不同,咱們通常而言的 函數/方法 ,都是一些statement的集合。也就是說,他能夠對外界環境進行改造 (好比網絡請求,數據庫請求),也能夠徹底沒有輸入和輸出,更不用提說什麼映射了。
但其實要想借鑑過來也很簡單,好比大多現代語言都引入了 閉包 , 一等公民 ,在此基礎上只須要給平常所寫的函數加一個約束,就能夠作到相似數學函數的效果。(加了這些約束的函數被稱爲 純函數 ,或 引用透明 )這個約束就是:沒有反作用(只能加工參數,輸出結果,不能修改外界環境)
若是咱們平時多寫純函數,問題就已經獲得了必定的簡化。
純函數 帶來的一個好處就是 不可變 immutability ,由於 純函數 只能處理輸入,返回輸出,那外界的狀態就能夠經過拷貝的方式傳遞進來,不用修改原來的值:
好比對於把x這個集合傳入各類各樣的函數內,x並不會改變。
這個好處不言而喻,不可變意味着線程安全,意味着沒必要由於一些bug去查看每個可能產生的函數。
例如Swift就引入了這個特性,除了 class 都是 值類型 ,傳遞即拷貝,並經過 copy-on-write 實現按需拷貝,下降空間開銷。
純函數 不是一個褒義詞,如同 反作用 不是一個貶義詞同樣。
有人肯花錢讓咱們作程序的緣由就是編寫程序經過寫一些不純函數來產生反作用(例如改變數據庫裏的數據)
用戶不關心代碼,只關心你能帶給他們什麼樣的 反作用 (其實對於他們就是想要的做用) ,只有程序員才關心這個過程夠不夠優雅。
問題在於如何處理 反作用 ?
答案是 橋 ,換句話說就是一層封裝,把真正要產生的 反作用 藏起來。調用 橋 只能經過一個如何修改該值的函數給它,由這層封裝來幫你實現 反作用 。
若是是狀態修改,有一種方式是:當有衝突發生的時候,會從新執行須要再次更新的函數。(相似數據庫的transaction)
若是是修改外部環境,通常會把請求放到隊列裏,統一派發。
即便是函數式語言, 反作用 也是要作的,否則這個程序就毫無心義,只是咱們把 反作用 和 純函數 隔離了起來,讓他們的影響在一個可控的範圍內。
這種隱藏狀態,經過傳遞函數修改狀態的管理 反作用 的方式,就是咱們下面要聊的狀態管理思想。
那就是併發!
共享全局狀態是維護的噩夢,單純的亂代碼還不足以形成沒法理解,能夠經過清理最終理清,但若是是併發問題的代碼,須要釜底抽薪的改造纔可能把各類線程間的協做交接清楚。
即便咱們不引入 狀態管理框架 ,僅僅是讓數組不可變,用Promise/RxSwift之類把異步的代碼梳理好,也至少能讓出現問題的線程拿到了不一樣版本的數據,因爲數據間的隔離就不會有這邊遍歷那邊修改致使的閃退。
若是在應用了Promise/RxSwift以外,引入了 狀態管理框架 ,就意味着有了一個方便的途徑,能夠直接聲明一種安全的共享狀態,全部的修改都是統一控制的,不只僅不會出錯,還可讓每次修改都能有序的生效。