摘要:發(fā)布訂閱作為一種常見的設(shè)計(jì)模式,在前端模塊化領(lǐng)域可以用來解決模塊循環(huán)依賴問題。訂閱函數(shù)管道化上面的例子基本可以滿足需求了,但是有時(shí)候我們希望多個(gè)訂閱函數(shù)之間可以傳遞執(zhí)行結(jié)果,類似管道這種,上一個(gè)函數(shù)的輸出是下一個(gè)函數(shù)的輸入。
發(fā)布訂閱作為一種常見的設(shè)計(jì)模式,在前端模塊化領(lǐng)域可以用來解決模塊循環(huán)依賴問題。
看一個(gè)簡單的示例// 消息中間件v1 var msghub = (function() { var listener = []; return { on: function(type, cb, option) { listener[type] = listener[type] || []; option = option || {}; listener[type].push({ cb: cb, priority: option.priority || 0 }); }, fire: function(type, dataObj) { if (listener[type]) { listener[type].sort((a, b) => a.priority - b.priority).forEach((item) => { item.cb.call(null, dataObj); }); } } } })();
以及消息中間件的使用模塊
// a.js msghub.on("data", function(data) { console.log(data.val + 1); // 3 }) // b.js msghub.on("data", function(data) { console.log(data.val + 2); // 4 }) // c.js msghub.fire("data", { val: 2 });
當(dāng)c模塊觸發(fā)data事件的時(shí)候,a和b模塊的監(jiān)聽函數(shù)都會(huì)被執(zhí)行并輸出相應(yīng)的結(jié)果。
訂閱函數(shù)管道化上面的例子基本可以滿足需求了,但是有時(shí)候我們希望多個(gè)訂閱函數(shù)之間可以傳遞執(zhí)行結(jié)果,類似linux管道a.pipe(b).pipe(c)…這種,上一個(gè)函數(shù)的輸出是下一個(gè)函數(shù)的輸入。針對這種管道化需求我們對msghub的回調(diào)遍歷從forEach改為reduce方式,如下代碼所示
// 消息中間件v2 支持執(zhí)行結(jié)果傳遞 var msghub = (function() { var listener = []; option = option || {}; return { on: function(type, cb, option) { listener[type] = listener[type] || []; listener[type].push({ cb: cb, priority: option.priority || 0 }); }, fire: function(type, dataObj) { if (listener[type]) { listener[type].sort((a, b) => b.priority - a.priority).reduce((pre, cur) => { let result = cur.cb.call(null, pre) || pre; // 如果一個(gè)訂閱函數(shù)沒有返回值則傳遞上上個(gè)訂閱函數(shù)的執(zhí)行結(jié)果,如果需要完全的管道化的話就把|| pre去掉即可 return result; }, dataObj); } } } })();
測試一下上面的msghub
// a.js msghub.on("data", function(data) { console.log("module a get num:" + data.val); // 3 return { val: ++data.val }; }) // b.js msghub.on("data", function(data) { console.log("module b get num:" + data.val) return { val: data.val + 3 } }) // d.js msghub.on("data", function(data) { console.log("module d get num:" + data.val); }) // e.js msghub.on("data", function(data) { console.log("module e get num:" + data.val); }) // c.js msghub.fire("data", { val: 2 });
使用改良后的msghub的話
// a.js msghub.on("data", function(data) { console.log("module a get num:" + data.val); // 3 return { val: ++data.val }; }) // b.js msghub.on("data", function(data) { console.log("module b get num:" + data.val) return { val: data.val + 3 } }) // d.js msghub.on("data", function(data) { console.log("module d get num:" + data.val); }) // e.js msghub.on("data", function(data) { console.log("module e get num:" + data.val); }) // c.js msghub.fire("data", { val: 2 });
最終打印輸出如下信息:
module a get num:2 module b get num:3 module d get num:6 module e get num:6訂閱函數(shù)支持異步
上面的例子中有一個(gè)問題就是訂閱函數(shù)必須是同步代碼,如果a.js包含下述異步代碼的話就會(huì)出問題
// a.js msghub.on("data", function(data) { console.log("module a get num:" + data.val); // 3 return new Promise(function(resolve, reject) { setTimeout(() => { resolve({ val: ++data.val }) }, 1000); }); })
針對可能同步可能異步的情況我們需要進(jìn)一步改良msghub來支持,該請asyn和await出場了
// 消息中間件v3 支持異步管道化 var msghub = (function() { var listener = []; return { on: function(type, cb, option) { listener[type] = listener[type] || []; option = option || {}; listener[type].push({ cb: cb, priority: option.priority || 0 }); }, fire: function(type, dataObj) { if (listener[type]) { let listenerArr = listener[type].sort((a, b) => b.priority - a.priority); (async function iter() { let val = dataObj; for (const item of listenerArr) { val = await item.cb.call(null, val); } })(); } } } })();
注意: 上述代碼可以在node環(huán)境做測試,如果需要在瀏覽器中運(yùn)行的話,需要對for of和async await進(jìn)行babel編譯
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/94986.html
摘要:寫代碼容易,寫出優(yōu)雅的代碼難,寫易于維護(hù)的容易擴(kuò)展的結(jié)構(gòu)清晰的代碼應(yīng)該是每位開發(fā)者努力的目標(biāo),而學(xué)習(xí)設(shè)計(jì)模式,合理的的使用能讓我們離這個(gè)目標(biāo)更進(jìn)一步。 寫代碼容易,寫出優(yōu)雅的代碼難,寫易于維護(hù)的、容易擴(kuò)展的、結(jié)構(gòu)清晰的代碼應(yīng)該是每位開發(fā)者努力的目標(biāo),而學(xué)習(xí)設(shè)計(jì)模式,合理的的使用能讓我們離這個(gè)目標(biāo)更進(jìn)一步。最近看了《Javascript設(shè)計(jì)模式與開發(fā)實(shí)踐》這本書,一言以蔽之,真不錯(cuò)的一本...
摘要:寫代碼容易,寫出優(yōu)雅的代碼難,寫易于維護(hù)的容易擴(kuò)展的結(jié)構(gòu)清晰的代碼應(yīng)該是每位開發(fā)者努力的目標(biāo),而學(xué)習(xí)設(shè)計(jì)模式,合理的的使用能讓我們離這個(gè)目標(biāo)更進(jìn)一步。 寫代碼容易,寫出優(yōu)雅的代碼難,寫易于維護(hù)的、容易擴(kuò)展的、結(jié)構(gòu)清晰的代碼應(yīng)該是每位開發(fā)者努力的目標(biāo),而學(xué)習(xí)設(shè)計(jì)模式,合理的的使用能讓我們離這個(gè)目標(biāo)更進(jìn)一步。最近看了《Javascript設(shè)計(jì)模式與開發(fā)實(shí)踐》這本書,一言以蔽之,真不錯(cuò)的一本...
閱讀 3628·2021-11-24 09:39
閱讀 2567·2021-11-15 11:37
閱讀 2222·2021-11-11 16:55
閱讀 5246·2021-10-14 09:43
閱讀 3716·2021-10-08 10:05
閱讀 3019·2021-09-13 10:26
閱讀 2337·2021-09-08 09:35
閱讀 3549·2019-08-30 15:55