immy框架已服役半年,回首這段歲月,她確實給我們帶來了非常重要的進(jìn)步——不會再出現(xiàn)諸如修改css時“牽一發(fā)而動全身”的恐懼。模塊化,強調(diào)了模塊的獨立、模塊之間的隔離,然而,有時還是需要一些通信。現(xiàn)在就有一個問題比較撓頭,拋出來探討
問題:如何共享從服務(wù)端取回的數(shù)據(jù)
有些時候,多個模塊都依賴于某一個api接口返回的數(shù)據(jù)(比如用戶信息接口)。彼時,為了保證模塊的獨立性,提倡“各個模塊如需要就自己去取”的做法。自然,這樣的做法就會導(dǎo)致同一個頁面會多次請求同一個接口,在性能上有一些損失。
現(xiàn)在,前端同學(xué)們有“共享”數(shù)據(jù)的傾向:即某一個模塊去取,取回之后放到全局的data里,其他模塊如需要就從這里來取。這樣做可以避免多次訪問同一接口,可是,有一個重要的問題必須得考慮:后者來取數(shù)據(jù)的時機(jī)。因為各個模塊的加載、ajax請求都是異步的,假設(shè)A模塊負(fù)責(zé)取數(shù)據(jù)(并放在全局),B模塊從全局取數(shù)據(jù)來用。那么,B模塊無法確切知道A模塊何時把數(shù)據(jù)準(zhǔn)備好。等待?等多久……不確定
一種確切的解決方法是:A模塊準(zhǔn)備好數(shù)據(jù)時主動調(diào)用B模塊的方法,來應(yīng)用數(shù)據(jù)。這無疑是引入了兩個模塊的硬關(guān)聯(lián),跟“模塊隔離”的思想是相悖的。怎么辦?
Event
使用Event機(jī)制,當(dāng)A模塊準(zhǔn)備好數(shù)據(jù)后,提交一個 data-ready 的Event。那些關(guān)注此Event(預(yù)先已經(jīng)注冊過)的模塊,就收到了明確的指示:現(xiàn)在數(shù)據(jù)ready了,你可以用了。
這種機(jī)制的一個進(jìn)步是:
- 提交某Event的模塊并不知道周圍誰關(guān)心此Event,只管在自己干完活之后吼一嗓子;
- 關(guān)注某Event的模塊也不知道是誰觸發(fā)此Event,只管在那里等待即可。
如此,不存在顯式的調(diào)用,比較解耦。
實現(xiàn)
大大們早已經(jīng)實現(xiàn)并廣泛應(yīng)用此機(jī)制,在npm上每天的下載量都是10萬,拿來用即可。
示意代碼
// 全局有一個EventEmitter的單例
project.events = new EventEmitter();
// 模塊A(提交Event)
some other logic...
$.ajax(..., {
success: function(json) {
project.data.userData = json.userData;
project.events.emit('user.data.ready'); // 提交Event
}
})
// 模塊B(消費Event)
some other logic...
project.events.addEventListener('user.data.ready', function() {
var user = project.data.userData;
// use it
});
// 模塊C(消費Event)
// 代碼類模塊B,按自己需要來應(yīng)用數(shù)據(jù)
注:
- addEventListener必須在event.emit之前執(zhí)行
- addEventListener有個別名: on(跟jquery的 $('...').on('click', ....) 的風(fēng)格一致)。熟悉這套機(jī)制后,可以少寫幾個字符。
- emit時可以將數(shù)據(jù)作為參數(shù)帶上,如不需將數(shù)據(jù)存到全局的話,可如此
OK, so long.