天天看點

更新 綁定資料_從觀察者模式與釋出-訂閱模式到雙向資料綁定簡單實作

1.背景

平時使用過 Vue 這個前端架構的同學,對于資料綁定這個詞肯定不會陌生,進一步,它與 react 有點不同的是它還有一個雙向資料綁定 v-model。

資料綁定的方式能夠極大程度上友善我們開發,不用去進行繁瑣的 DOM 操作,這也是 MVVM 架構的一個極大的優勢所在。

網上閱讀到其他同學對 Vue 源碼解讀的文章,發現大家對 Vue 的依賴收集機制解讀會有些不一樣的方式。有些同學解釋說依賴收集使用的觀察者模式,有些同學則解釋說是釋出/訂閱模式。

因為以前認為這兩個名字隻是不同的叫法而已也就沒太在意,但偶然發現有人問這兩個模式的差別,這個問題突然也引起了我的好奇心,是以也就花了些時間來比較這兩個名詞背後到底有什麼不同。

更新 綁定資料_從觀察者模式與釋出-訂閱模式到雙向資料綁定簡單實作

2.兩個模式的異同

更新 綁定資料_從觀察者模式與釋出-訂閱模式到雙向資料綁定簡單實作

觀察者模式與釋出-訂閱模式

首先直接上圖。從圖中可以看出,無論是觀察者模式還是釋出-訂閱模式,它們都是一些狀态依賴于某些資料,當資料發生變化,這些狀态也需要進行相應的更新的模式。不同點在于,釋出-訂閱模式比觀察者模式多了個事件中心。

更細緻點說,在觀察者模式中,被觀察者能夠完全感覺到觀察者的存在,一旦發生變化,被觀察者負責将變化通知到所有的觀察者。

舉個例子,假設你要出租一套房子,你在網上釋出了資訊,有很多人聯系你。當你的房子租出去之後,你要将這個資訊通知到剩下的其他人,讓他們去租别的房子。

更新 綁定資料_從觀察者模式與釋出-訂閱模式到雙向資料綁定簡單實作

而在釋出-訂閱模式中,因為有個事件中心的存在,當釋出者釋出新的資訊之後,事件中心會去通知更新。

還是出租房子的例子,你把你要出租房子的資訊告訴中介,同時中介那邊有很多客戶讓中介幫忙找房,當你的房子租出去後,你隻需要告訴中介房源沒了,中介則會去通知意向客戶房源缺失的資訊。

在該模式中,訂閱者向事件中心訂閱某些事件,釋出者并不知道有沒有訂閱者,隻要發生變化,釋出者就會通知事件中心。

下面就用實際的代碼來還原一下這兩個模式。

3.觀察者模式

ObserverList.js

觀察者清單類,由被觀察者管理,添加或移除對應的觀察者。

更新 綁定資料_從觀察者模式與釋出-訂閱模式到雙向資料綁定簡單實作

Observer.js

觀察者類,接到更新通知後,做出一些回報。

更新 綁定資料_從觀察者模式與釋出-訂閱模式到雙向資料綁定簡單實作

Observed.js

被觀察者類,負責維護觀察者,并且将更新通知到所有觀察者。

更新 綁定資料_從觀察者模式與釋出-訂閱模式到雙向資料綁定簡單實作

index.js

更新 綁定資料_從觀察者模式與釋出-訂閱模式到雙向資料綁定簡單實作

4.釋出-訂閱模式

EventCenter.js

事件中心類,包括處理訂閱者的訂閱/退訂事件,以及釋出者釋出事件後的變更通知。

更新 綁定資料_從觀察者模式與釋出-訂閱模式到雙向資料綁定簡單實作

Publisher.js

釋出者類,負責向事件中心釋出變更。

更新 綁定資料_從觀察者模式與釋出-訂閱模式到雙向資料綁定簡單實作

Subscriber.js

訂閱者類,對變更通知做出回報。

更新 綁定資料_從觀察者模式與釋出-訂閱模式到雙向資料綁定簡單實作

index.js

更新 綁定資料_從觀察者模式與釋出-訂閱模式到雙向資料綁定簡單實作

5.小結

總的來說,兩種設計模式都是為了解耦,其中釋出-訂閱模式解耦度更高。也可以認為釋出-訂閱模式是觀察者模式的進一步解耦,這也是有時候會認為這兩個模式一樣。

現在反過來看 Vue 中的依賴搜集,它更多的傾向于觀察者模式,因為對于某個資料的觀察,擁有該資料的對象都能清楚的感覺,當資料變化後,它都要通知到各個依賴對象。

有人認為觀察者模式更多的是同步操作,而釋出-訂閱模式更适合異步操作(引入消息隊列),但就 Vue 來說,它在派發更新過程中,也引入了隊列的概念,Vue 并不是每當資料更新就立馬響應,而是放入一個隊列,在下一個 Tick 中再将該隊列整個重新整理。

6.用釋出-訂閱模式實作資料綁定

既然前面已經知道 Vue 是通過觀察者模式來實作依賴收集的,那這裡就用釋出-訂閱模式來簡單實作一下資料綁定的功能!

更新 綁定資料_從觀察者模式與釋出-訂閱模式到雙向資料綁定簡單實作

說幹就幹!

先讓我們來分析一下做這個例子的流程。

1、首先,我們需要一個事件中心eventCenter,能夠滿足 DOM 節點對響應式資料變化的訂閱,能夠在資料變化後釋出資訊給 DOM 節點。

2、其次,我們需要對所有的響應式資料進行攔截,用Object.defineProperty方法進行改寫,主要是在set函數中通過事件中心釋出變化。

最後,我們需要對管理的 DOM 節點進行周遊,将{{ 響應式變量 }}替換為實際資料,并且對資料進行變更訂閱。

既然流程搞清楚了,那就開始撸代碼吧!

Coding…

  • eventCenter.js
更新 綁定資料_從觀察者模式與釋出-訂閱模式到雙向資料綁定簡單實作
  • dataBinding.js
更新 綁定資料_從觀察者模式與釋出-訂閱模式到雙向資料綁定簡單實作
  • index.html
更新 綁定資料_從觀察者模式與釋出-訂閱模式到雙向資料綁定簡單實作

eventCenter.js就是事件進行中心,dataBinding.js就是完成資料綁定的主要邏輯操作了。

在周遊所有 DOM 節點的時候,對于文本節點,用正規表達式判斷是否引用響應式資料,如果有則進行相應的替換,對于标簽節點,首先判斷是不是input節點,因為需要對v-model做雙向綁定操作,然後再通過遞歸進行子節點的篩選。

結果示範

更新 綁定資料_從觀察者模式與釋出-訂閱模式到雙向資料綁定簡單實作

相較于 Vue 的實際資料綁定的實作,這個 demo 肯定是極其簡略甚至粗糙的(╭(╯^╰)╮)~比如說,一個标簽節點中既有普通文本,又有響應式資料,或者一個标簽裡有多個資料綁定,這些都沒處理。

但通過這個簡單的例子,加深了自己對于 Vue 資料綁定的了解還是很有意義的~