1. 程式人生 > >用訂閱/發布者模式解決異步函數結果依賴的問題

用訂閱/發布者模式解決異步函數結果依賴的問題

nts 簡單 time res llb 回調 不能 urn event

我們都知道node是基於事件無阻塞i/o模型的,所以說大部分函數都是以異步實現的,請看下面代碼:

db.query(sql1, function (err, data) {
    //code
})

db.query(sql2, function (err, data) {
    //code
})

如果我們上述兩個操作,結果之間沒有什麽聯系,那很好,基於node的I/O無阻塞模型,每個操作都做著自己的事情,美滋滋~

但是在一些情況下這兩個操作的結果有聯系的,比如說第一個操作從數據庫中取出一個人的姓,第二個操作從數據庫中取出同一個人的名。

假設我們有一個需求就是我們要把這兩個操作的結果組合起來變成一個人的姓名(這個操作貌似有點浮誇,嘻嘻),也就是說我們要組合成姓名這個操作必須是在姓和名都取到的情況下才能進行,可達鴨眉頭一皺,發現事情並不簡單。我們知道上述兩個操作是異步操作,他們何時結束我們根本不能知道,只知道他結束時會執行回調函數。下面我們就用訂閱發布者模式來解決它。請看下面代碼:

var count = 0;
var results = {};
var done = function (key, value) {  //訂閱,姓和名進行訂閱
    results[key] = value;
    count++;

    if(count === 2) {
        //發布,也就是執行剛剛說的組成姓名的操作
var name = results.lastName + results.firtName;
} } db.query(sql1, function (err, data) { //這裏data我們假設是從數據庫取到姓 done("lastName", data); }) db.query(sql2,
function (err, data) { //這裏data我們假設是從數據庫取到名 done("firstName", data); })

這樣一來,每個i/o完成都會執行done方法,把取到的數據存到results對象中,也就是訂閱,而當訂閱數等於2的時候,也就是兩個操作都完成並且都把數據存在results中了,那麽就可以發布,也就是執行組成姓名的操作。利用訂閱/發布者模式實現多對一,基本完成了我們的需求,但是這樣的代碼是醜陋的,我們用閉包和偏函數把代碼優化並且抽象一下,以適合更多的需求。改進代碼如下:

var after = function (times, callback) {
    
var count = 0, results = {}; return function (key, value) { results[key] = value; count++; if(count === times) { callback(); } }; }; //對閉包的引用 var done = after(times, render);

ps:利用node的events模塊我們還可以實現訂閱/發布者的多對多模式。

參考資料:深入淺出Node.js第4章

用訂閱/發布者模式解決異步函數結果依賴的問題