2011-07-29 30 views
3

有一個函數需要調用不確定數量的其他(可能是異步)函數,每個函數都帶有回調函數,我正在使用以下模式。,使用回調執行多個異步函數的最佳實踐是什麼?

雖然很確定它是正確的,但不是很美觀。

 
// fn responsible for figuring out and calling aysnc funcs 
function fn(arg, outNext) { 

     // calculate how many funcs we will be calling 
     var waitCt = 0; 
     var a, b, c; 
     if(a = arg['a']) waitCt++; 
     if(b = arg['b']) waitCt++; 
     if(c = arg['c']) waitCt++; 

     // call funcs 
     if(a) fnArbitrary(arg.a, inNext); 
     if(b) fnRandom(arg, inNext); 
     if(c) fnClueless(15, inNext); 

     // calback func 
     function inNext(err) { 

       // wait for one less func 
       waitCt--; 

       // return err if found 
       if(err) outNext(err); 

       // return nada if all funcs performed 
       if(waitCt == 0) outNext(); 

       // otherwise we're waiting for other funcs to finish 
       return; 
     } 
} 

對我來說,似乎有必要採取兩個步驟:第一,看看有多少funcs中會被調用,第二個做的呼喚。但是也許我的大腦是從老派編程或者昨晚讀了太多李爾的東西而變得糟糕透頂。

+0

不清楚您定義fa,fb和fc的位置。你能不能給你的函數發一個示例調用? – mamoo

+0

@mamoo - fa,fb和fc是具有回調功能的任意函數,例如發佈或讀取數據庫。 (這裏的實際代碼非常大並且糾結) –

回答

3

我已經看到了多個aysnc功能最好的經營理念是Deferreds及期貨描述in this Script Junkie articlethis article about the FutureJS implementationthis msdn article這個Stack Overflow question

它實際上是一種考慮對多個異步調用進行排序或定義它們之間的執行依賴關係的結構化方式,它似乎對多種實現(已經可用)對不同框架具有牽引力,因此它似乎是一個普遍支持的想法有用於現在和未來學習。

管理多個具有依賴關係的異步調用手工確實很麻煩。代碼不僅看起來很混亂,而且不可能閱讀,甚至不可能使用調試器。調試通常需要將大量信息轉儲到日誌文件,然後嘗試整理髮生的事情。如果涉及時間的話,那你真的是一團糟。在我上一個項目中,我仍然有一個未解決的bug的唯一區域是在啓動時四種不同的異步調用之間的某種錯過的依賴關係。我強化了代碼,使它幾乎從不發生錯誤,但它還沒有完全消失。下一步是切換到使用延遲並添加一些正式的結構。

至於一些較大的庫,我們有jQuery Defereds,YUI3具有Async Queue(比一般deferreds那麼強大,但是很有用),道場有一個Deferred object並且有未綁定到一對夫婦推遲庫主圖書館。

+0

瞭解node.js的承諾,但認爲它們距離普遍實施還有很遠的距離 –

+0

「通用實施」對於當前情況聽起來有點過於強大,但該概念似乎具有牽引力並有實現可供使用。我還沒有親眼看到其他任何可以更有吸引力地乾淨利落的東西。 – jfriend00

+0

您引用的主庫來自msdn。這是你用的嗎? (請原諒我(毫無理由)對源自ms的代碼的不信任。) –

1

我有一個after after utility函數。

var after = function _after(count, f) { 
    var c = 0, results = []; 
    return function _callback() { 
    switch (arguments.length) { 
     case 0: results.push(null); break; 
     case 1: results.push(arguments[0]); break; 
     default: results.push(Array.prototype.slice.call(arguments)); break; 
    } 
    if (++c === count) { 
     f.apply(this, results); 
    } 
    }; 
}; 

// fn responsible for figuring out and calling aysnc funcs 
function fn(arg, outNext) { 

    var cb = after(Object.keys(arg).length, function(data) { 
     // all finished. Do something 
    }); 

    // replace fa, fb, fc with f['a'], f['b'], f['c'] 
    Object.keys(arg).forEach(function(k) { f[k](arg[k], cb); }); 
} 

這應該用於簡單情況。對於更復雜的情況下使用某種形式的流量控制就像Futures

+0

不知道這將如何工作。你在調用'after()'後有「3」硬連線,但實際被調用的函數的數量需要傳遞給'after()' - 對嗎? - 或者我錯過了什麼? –

+0

@cc_young這是一個錯誤。傳遞'Object.keys(arg).length'只會針對存在的參數數量。這應該具有期望的行爲 – Raynos

相關問題