16

我試圖找到最好的方式來創建異步調用時,每個電話取決於先前的呼叫已完成。目前我通過遞歸調用定義的過程函數來鏈接方法,如下所示。在javascript中鏈接異步調用的正確方法是什麼?

這就是我目前正在做的。

var syncProduct = (function() { 
    var done, log; 
    var IN_CAT = 1, IN_TITLES = 2, IN_BINS = 3; 
    var state = IN_CAT; 
    var processNext = function(data) { 
     switch(state) { 
      case IN_CAT: 
       SVC.sendJsonRequest(url("/api/lineplan/categories"), processNext); 
       state = IN_TITLES; 
       break; 
      case IN_TITLES: 
       log((data ? data.length : "No") + " categories retrieved!"); 
       SVC.sendJsonRequest(url("/api/lineplan/titles"), processNext); 
       state = IN_BINS; 
       break; 
      case IN_BINS: 
       log((data ? data.length : "No") + " titles retrieved!"); 
       SVC.sendJsonRequest(url("/api/lineplan/bins"), processNext); 
       state = IN_MAJOR; 
       break; 
      default: 
       log((data ? data.length : "No") + " bins retrieved!"); 
       done(); 
       break; 
     } 
    } 
    return { 
     start: function(doneCB, logCB) { 
      done = doneCB; log = logCB; state = IN_CAT; 
      processNext(); 
     } 
    } 
})(); 

我會再調用這個如下

var log = function(message) { 
    // Impl removed. 
} 

syncProduct.start(function() { 
    log("Product Sync Complete!"); 
}, log); 

雖然這工作完全正常了我,我不能幫助,但認爲必須有一個更好的(簡單)的方式。當我的遞歸調用變得太深時,會發生什麼?

注意:我沒有在瀏覽器中使用JavaScript,但本機在鈦框架內,這是類似於Node.js的Javascript。

+1

你看過「承諾」嗎?他們可能很好。 [這是一個爲Node實現的庫](https://github.com/kriskowal/q)。 – pimvdb 2012-02-24 14:46:43

+0

那個庫看起來很棒pimvdb,我想我會用這個。 – 2012-02-25 06:37:35

回答

26

有很多庫和做異步鏈接和控制流爲你的工具,他們大多有兩種主要形式:

  1. 控制流動圖書館

    例如,參見async,seqstep(基於回調)或Qfutures(基於承諾)。這些的主要優點是它們只是平臺JS庫,可以緩解異步編程的痛苦。

    根據我個人的經驗,基於承諾的庫往往會導致代碼看起來更像通常的同步代碼,因爲您使用「return」返回值,並且由於承諾值可以傳遞並存儲,與實際值類似。

    另一方面,基於continuation的代碼是更低級的,因爲它明確地操縱代碼路徑。這可能允許更靈活的控制流程和更好的與現有庫的集成,但也可能導致更多的樣式化和不太直觀的代碼。

  2. 的Javascript CPS編譯器

    擴展語言增加對協同程序/發電機的原生支持,您可以在一個非常直接的方式編寫異步代碼彈奏優美的語言其餘這意味着你可以使用JavaScript如果語句,循環等,而不需要用函數複製它們。這也意味着它很容易將先前的同步代碼轉換爲異步版本。然而,有一個明顯的缺點,並不是每個瀏覽器都會運行你的Javascript擴展,所以你需要在你的構建過程中添加一個編譯步驟,將你的代碼轉換爲常規JS,並使用延續傳遞樣式的回調。無論如何,一個有希望的替代方案是Ecmascript 6規範中的生成器 - 雖然Firefox目前只支持它們,但有些項目(如regeneratorTraceur)將它們編譯回回調函數。還有其他項目可以創建自己的異步語法(因爲es6生成器還沒有出現)。在這個類別中,你會發現諸如tamejsIced Coffeescript之類的東西。最後,如果您使用Node.js,那麼您還可以查看Fibers


我recomendation:

如果你只是想簡單的東西,不會您的構建proccess複雜的是,我會建議與任何控制流庫最適合您的個人風格會和你已經使用的庫。但是,如果您希望編寫大量複雜且深度集成的異步代碼,我強烈建議至少查看基於編譯器的替代方案。

+0

優秀的缺失,pimvdb在我的問題的評論中也提到的'Q'庫看起來很完美。在我決定走上一條道路之前,您能否對圖書館提供任何反饋意見?我想我不想要的是第一次調用時完全阻塞的調用。 – 2012-02-25 06:41:25

+2

@BrettRyan:實際上,我主要使用Dojo工具包,所以我對自己的承諾庫擁有大部分經驗,對替代方案沒有太多經驗。所有不同的風格都應該能夠完成所有你需要的非阻塞的東西,所以你應該更多地看待編程風格。如果我現在不得不開始一些工作,我會認真考慮使用CPS編譯器 - 我真的不知道它會如何實際發生,但現在我厭倦了手動編寫CPS代碼並希望得到某些東西更好。 – hugomg 2012-02-25 16:28:56

+0

感謝missno,我正在使用Appcelerator Titanium Mobile SDK,因此不想將其他工具放入工具鏈中。對Q庫進行實驗確實看起來很合適。 – 2012-02-25 22:51:17

相關問題