摘要:所以,單向數據流的意思是指在變更檢測期間屬性綁定變更的架構。相反,輸出綁定過程并沒有在變更檢測期間內運行,所以它沒有把單向數據流轉變為雙向數據流。說的單向數據流說的是服務層,而不是視圖層嗷。
原文鏈接: Do you really know what unidirectional data flow means in?Angular
關于單向數據流,還可以參考這篇文章,且文中還有 youtube 視頻解析:Angular - What is Unidirectional Data Flow? Learn How the Angular Development Mode Works, why it"s important to use it and how to Troubleshoot it 。單向數據流一句話解釋就是:不要在 Angular 使用 Model 生成 View 這個過程中再去修改 Model。
大多數架構模式是很難理解的,尤其是在相關資料很少時那就更加頭疼,比如 Angular 的單向數據流(unidirectional data flow)文檔資料就很少,即使官方文檔上,也僅僅在 表達式指南 和 模板表達式 兩小塊中略有提及。我也很少在網上搜到比較好的解釋文章,所以寫此文是為了給 單向數據流(unidirectional data flow) 有個詳細的解釋。
雙向數據流和單向數據流在討論 AngularJS 和 Angular 性能異同點時,就經常會提到單向數據流模式,它也是 Angular 比 AngularJS 性能更快的原因所在。讓我們一起看看單向數據流究竟咋回事吧!(譯者注:AngularJS 指的是 1.X 版本,2+ 版本叫 Angular,使用 TypeScript 語言重寫了框架,包括架構模式進行了重新設計,但兩者形似也神似。)
AngularJS 和 Angular 都是通過綁定來實現組件間數據通信,比如在 AngularJS 定義一個父組件 A:
app.component("aComponent", { controller: class ParentComponent() { this.value = {name: "initial"}; }, template: `` }); ---------------- app.component("bComponent", { bindings: { obj: "=" },
可以看到父組件 A 有個子組件 B,并且通過輸入綁定把父組件 A 的 value 屬性值傳給子組件 B 的 obj 屬性:
這和 Angular 中組件間通信很類似了啊:
@Component({ template: `... export class AppComponent { value = {name: "initial"}; } ---------------- export class BComponent { @Input() obj;
第一件重要的事情是,Angular 和 AngularJS 都是在變更檢測(change detection)期間才去更新綁定值。所以,當 Angular 框架在為父組件 A 運行變更檢測時,它會更新子組件 B 的 obj 屬性:
bComponentInstance.obj = aComponentInstance.value;
上面過程證明了單向數據流是數據從上往下流(譯者注:即數據從組件樹的父組件往子組件流),但是 AngularJS 卻不一樣,它可以允許在子組件中更新父組件的 value 屬性值:
app.component("parentComponent", { controller: function ParentComponent($timeout) { $timeout(()=>{ console.log(this.value); // logs {name: "updated"} }, 3000) } ---------------- app.component("childComponent", { controller: function ChildComponent($timeout) { $timeout(()=>{ this.obj = { name: "updated" }; }, 2000)
上面代碼你可以看到兩個 timeout 回調,第一個回調會更新子組件屬性,第二個回調會延遲第一個回調一秒,檢查父組件屬性是否被更新。如果你在 AngularJS 中運行上面代碼你會發現父組件屬性已經被更新了。讓我們一起看看究竟發生了什么?
當第一個回調運行時,子組件 B 的 obj 屬性被更新為 {name: "updated"},然后 AngularJS 運行變更檢測。在變更檢測過程中,AngularJS 檢測到子組件綁定屬性的值發生改變,它會更新父組件 A 的 value 屬性值。這是 AngularJS 變更檢測的內置功能。如果你在 Angular 中做同樣的事情,它僅僅更新子組件的屬性值,但是子組件的改變不會冒泡到父組件,即 Angular 不會改變父組件的屬性值。這是升級版后的 Angular 變更檢測實現,相較于 AngularJS 的最重大區別。然而,它卻困擾了我好久啊。
然而,Angular 也同樣可以通過子組件來更新父組件,這個機制就是輸出綁定(output binding)。可以像這樣使用輸出綁定:
@Component({ template: `Hello {{value.name}}
... export class AppComponent { value = {name: "initial"}; constructor() { setTimeout(() => { console.log(this.value); // logs {name: "updated"} }, 3000); ---------------- @Component({...}) export class AComponent { @Output() updateObj = new EventEmitter(); constructor() { setTimeout(() => { this.updateObj.emit({name: "updated"}); }, 2000);
我承認這個和從子組件直接更新還不太一樣,但是父組件值的確是更新了啊。很長一段時間我不明白為何這沒有被看做雙向數據綁定?畢竟,數據通信是在兩個方向進行的。
直到有一晚我讀到了 Two Phases of Angular Applications?by?Victor Savkin,他解釋道(譯者注:為清晰理解,這個解釋不翻譯):
Angular 2 separates updating the application model and reflecting the state of the model in the view into two distinct phases.?The developer is responsible for updating the application model. Angular, by means of change detection, is responsible for reflecting the state of the model in the view.
(譯者注:意思就是 Angular 劃分了更新程序 model在前和 同步 model 和 view在后兩個步驟,開發者只需要關注更新程序 model,同步 model 和 view 由 Angular 框架負責,這個同步過程就是變更檢測,說白了就是更新 view。)
(譯者注:比如朋友圈點贊,首先就是手指觸發異步事件來更新程序 model,如在 Post 組件里給 likes 屬性加 1,然后在下一個 VM turn 時 Angular 會自動更新視圖中綁定的 likes 值, 即同步 model 和 view,點贊數就會從 0 變為 1。)
這讓我花費好些天才明白,所謂的使用輸出綁定機制來更新父組件并不是在變更檢測中執行的:
相反,它是在變更檢測前的更新程序 model 階段執行的。所以,單向數據流的意思是指在變更檢測期間屬性綁定變更的架構。在上面 Angular 代碼示例中,不像 AngularJS,在 Angular 變更檢測期間,并沒有代碼去讓子組件 AComponent 去更新父組件 AppComponent 的屬性。相反,輸出綁定過程并沒有在變更檢測期間內運行,所以它沒有把單向數據流轉變為雙向數據流。
另外,盡管 Angular 沒有內置機制可以使得在變更檢測期間去更新父組件,然而可以通過共享服務或廣播同步事件做到這一點。但是,由于 Angular 框架強迫單向數據流,所以這么做會導致ExpressionChangedAfterItHasBeenCheckedError 錯誤。想要了解導致這個錯誤的原因和解決方案可以參考 Everything you need to know about the ExpressionChangedAfterItHasBeenCheckedError。
視圖和服務層的單向數據流你可能知道,大多數 web 程序會設計成有兩層:視圖層和服務層。
Web 環境下視圖層主要通過 DOM 結構向用戶展示相關程序數據,在 Angular 中這一層是通過組件做的。服務層主要是處理和保存數據,正如上圖中展示的,這一層又被切分為狀態管理和一些基礎部分,如 rest 服務或可重用工具服務(helpers)。
上文中提到的單向數據流指的是視圖層,因為它說的是組件,而組件是用來構建視圖的:
然而,在隨著實現了 redux 架構的 ngrx 引入后,這又讓人迷惑了,因為 redux 文檔上有 這么一句(譯者注:為清晰理解,這句不翻譯):
Redux architecture revolves around a?strict unidirectional data flow.
This means that all data in an application follows the same lifecycle pattern, making the logic of your app more predictable and easier to understand…
實際上,這個嚴格單項數據流(strict unidirectional data flow)其實說的是服務層而不是視圖層。但我有時會搞混服務層和視圖層,會把 redux 的架構模式與 Angular 的結構模式聯系起來,當然要避免搞混這兩層嗷。Redux 說的單向數據流說的是服務層,而不是視圖層嗷。 Redux 主要說的是狀態管理模塊,會把我們上文說的雙向數據流轉變為單向數據流。
把雙向數據流:
轉換為單向數據流:
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/93681.html
摘要:你是一個對感興趣的開發者嗎不用擔心,這真的不會讓你成為一個背叛者或其他什么,真的。事實上,這個想法并不是或獨創的它只是一種很棒的軟件開發實踐方式。把代碼分離到不同的文件里并不會自動導致關注點分離。 原文鏈接 : Getting to Grips with React (as an Angular developer)原文作者 : DAVE CEDDIA譯者 : 李林璞(web前端領域)...
摘要:自己英語一般,水平有限,獻上原文地址,還有我翻譯的中文地址,歡迎大家勘誤下面是自己的一點感想先說一下,我們知道,前端優化有這么幾步,第一步首先呢我們知道,一個應用要依賴好多條文件,而瀏覽器加載完一條,要執行完這條才加載下一條,所以呢,就很慢 自己英語一般,水平有限,獻上原文地址,還有我翻譯的中文地址,歡迎大家勘誤 下面是自己的一點感想 先說一下webpack,我們知道,前端優化有這么幾...
摘要:共享數據的最佳策略是什么呢用一些變態的控制器繼承方案嗎當然不是,最簡單容易的方式就是使用服務。概括創建一個服務去存放你的數據,并給數據創建和的方法。 原文鏈接 : Sharing Data Between Controllers? Best Practice: Use a Service原文作者 : DAVE CEDDIA譯者 : 李林璞(web前端領域)譯者注:翻譯如有疏漏,歡迎指出...
摘要:避免脆弱的基類問題。紅牌警告沒有提到上述任何問題。單向數據流意味著模型是單一的事實來源。單向數據流是確定性的,而雙向綁定可能導致更難以遵循和理解的副作用。原文地址 1. 你能說出兩種對 JavaScript 應用開發者而言的編程范式嗎? 希望聽到: 2. 什么是函數編程? 希望聽到: 3. 類繼承和原型繼承的不同? 希望聽到 4. 函數式編程和面向對象編程的優缺點? ...
閱讀 3776·2021-08-30 09:47
閱讀 3703·2019-08-30 15:56
閱讀 680·2019-08-30 14:18
閱讀 702·2019-08-29 16:17
閱讀 2069·2019-08-29 11:07
閱讀 647·2019-08-26 13:53
閱讀 3449·2019-08-26 10:26
閱讀 2497·2019-08-23 18:30