2012-09-17 77 views
1

我這就需要執行一些開機/啓動喜歡的應用程序:如何處理這些異步函數(?設計模式)

  • AJAX
  • 動態requirejs
  • 路由,建立了別的東西

之前能夠運行。

我現在遇到困難一起組織這些任務。 特別是異步行爲讓我頭痛。 目前我正在使用事件來共享獲取的結果並觀察應用程序的狀態。不幸的是,這導致了生態,不方便的廢話。 然後我嘗試使用一些promise類庫,如q,jquery.defered,但它們並不真正符合我的問題。

這是代碼的簡化版本:

// this could be an ajax call fetching some user data 
var fetchUser = function() { 
    var user = {}; 
    // lets emulate the ajax call with setTimeout 
    setTimeout(function() { 
     // set some values 
     user.username = 'bodo'; 
     user.password = 'helloKitty'; 
     // return the user object we "fetched" 
     return user; 
    }, 300); 
}; 

// this could fetch some config or some requirejs modules 
var fetchConfig = function() { 
    var config = {}; 
    // we emulate this too... 
    setTimeout(function() { 
     return config; 
    }, 200); 
}; 

// this could be anything else like setting up some objects 
var justSetUpSomething = function() { 
    var someObj = {}; 
    someObj.router = 'this could be a router object for example'; 
    someObj.logger = 'or a logger'; 
    return someObj; 
}; 

// in the final step everything should be merged together 
// and be passed as event argument 
var finalStep = function(user, config, someObj) { 
    var mainObj = {}; 
    mainObj.user = user; 
    mainObj.config = config; 
    mainObj.someObj = someObj; 
    // trigger some event system 
    trigger('everything:ready', mainObj); 
};​ 

還可以看到在: http://jsfiddle.net/uzJrs/3/

我希望這說明我的問題:

有三種完全不同的,異步任務。當他們都準備好時,他們的結果必須合併,並以某種方式傳遞給另一個對象。

事件使這可行但遠非可以理解和承諾的方式也不真正讓我開心。 沒有其他有用的設計模式嗎?

+0

Deferreds真正做到這一點。 – Bergi

+0

@Bergi我以爲他們只會幫助反對'厄運金字塔'?你也在建立一個對lib的依賴。但是你有沒有例子? – bodokaiser

回答

2

首先,如你哈已經有requirejs,你可以用它來加載你的三個模塊。 Requirejs解析異步和並行的依賴關係,並在加載時調用最終的工廠函數。

但是,每個Deferred庫也提供合併承諾的功能:合併的一個解決所有單個的問題,或者如果其中一個被拒絕,則會被拒絕。對應的函數分別Q.alljQuery.when

function fetchX() { 
    var d = new $.Deferred(); 
    asynchronousThing(function callback(x) { 
     d.resolve(x); 
    }); 
    return d.promise(); 
} 
$.when(fetchX(), fetchY(), …).then(function finalStep(x, y, …) { 
    // merge everything together 
    return new Event(); 
}).done(function readyCallback(e) { 
    // this is effectively your 'everything:ready' "event" 
}); 
+0

你可以給我一個jQuery.when的例子,當被攻擊對象不是ajax函數(例如自定義函數)嗎? – bodokaiser

+0

你還有什麼東西是異步的? – Bergi

+0

例如,動態requirejs加載。但是我注意到你可以將一個函數封裝到$ .Defered()中,以便在使用 – bodokaiser

1

聽起來像多數您的功能其實只要依賴被解決(即configsomeObj不要做任何異步他們只是可能會被異步加載。如果您正在使用require.js同步的你嘗試過乾脆利用其功能是通過使用define使從代碼的角度來看,require電話同步?如果你只需要擔心它必須是異步調用(fetchUser)。

// In app/main.js perhaps? 
define(["data/user", 
      "app/config", 
      "app/someObject", 
      "app/events"], 
    function(user, config, someObj, eventBus) { 
     // By the sound of it config and someObj are ready once loaded 
     var mainObj = {"config": config, "someObj": someObj}; 
     eventBus.register_once("data:user:loaded", function(user) { 
      mainObj.user = user; 
      eventBus.trigger("everything:ready", mainObj); 
     }); 
     user.fetchUser() 
}); 

// in data/user.js 
define(["app/config", "app/events", "vendor/jquery"], 
    function(config, eventBus, $) { 
     function user_loaded(user) { 
      eventBus.trigger("data:user:loaded", user); 
     } 
     function fetchUser() { 
      $.get(config.dataendpoint + "/user/1", user_loaded); 
     } 
    return {"fetchUser": fetchUser}; 
}); 
+0

我也使用requirejs依賴項數組作爲define參數。只是你必須知道你想知道什麼。如果你不知道它或者想要動態保存東西,那麼你需要手動加載異步。同樣,如果您對模塊具有雙向依賴關係。 – bodokaiser