2013-10-12 75 views
0

我想使輸出一組關於我的應用的健康指標,例如背景隊列長度,響應時間來服務依賴性等的模塊這是節點JS使用DeferredNodeJS中承諾數組的承諾延期?

var metrics = { 
    queueLength: function(def) { 
     // .. Do some stuff to resolve the queue length .. 
     def.resolve(45); // Example 
    } 
    // ... more metrics 
} 
for (i in metrics) { 
    def = deferred(); 
    metrics[i](def); 
    promiselist.push(def.promise); 
    def.promise(function(result) { 
     metrics[i] = result; 
    } 
} 
return deferred(promiselist)(function(result) { 
    console.log('All metrics loaded', result, metrics); 
}); 

這產生輸出

Metrics loaded [ [Function] ] { queueLength: [Function] } 

當我本來期望:

Metrics loaded [ 45 ] { queueLength: 45 } 

我覺得我做的兩件事情錯了,但不知道如何糾正這些「正常」:

  • return deferred([array of promises])(group promise)想法似乎並沒有工作
  • 我剛剛意識到def所以如果我是越來越在每次迭代重用多個指標可能只會跟蹤最後一個指標。

回答

0
metrics[i] = result; 

這是一個壞主意。您不應該銷燬metrics對象,它的屬性應該是並保持功能。如果你想要一個結果對象,建立一個新的結果。

推遲返回([承諾陣列])(集團承諾)的想法似乎並沒有工作

the docs和代碼,你可以看到,庫不支持數組參數。您將需要使用apply

deferred.apply(null, promiselist) 

我剛剛意識到高清在每次迭代是越來越重複使用,所以如果我有多個指標的話,大概只跟蹤最後一個。

不,它沒有得到重用,你正在每個循環中創建一個新的延遲對象。但是,您忘記了var keyword以使本地變量。

i變量也存在問題 - 它不在每個promise回調的閉包範圍內,這意味着當回調被解析時,變量已經具有最後一個循環的值。檢查JavaScript closure inside loops – simple practical example

一個小的設計缺陷是metrics方法確實將延遲作爲他們將要解決的參數。如果他們確實不採取任何爭論,並且爲他們自己創造(並管理)的結果返回承諾,那將會更好。

var metrics = { 
    queueLength: function() { 
     var def = deferred(); 
      // .. Do some stuff to resolve the queue length .. 
      def.resolve(45); // Example 
     return def.promise; 
    } 
    // ... more metrics 
}; 

var results = {}, 
    promiselist = []; 
for (var p in metrics) { 
    promiselist.push(metrics[p]().aside(function(_p) { 
     return function(result) { 
      results[_p] = result; 
     }; 
    }(p))); 
} 
return deferred.apply(null, promiselist).then(function(resultArr) { 
    console.log('All metrics loaded', resultArr, results); 
    return results; 
}); 
1

我同意Bergi指出的大部分事情。你不應該銷燬metrics方法,你應該在它們內部創建並返回promise。

這裏也有一些其他方面的改進,你可以這樣做:

deferred.map(命名爲對應於[].map),這是專門用於列表和數組,你可以直接用它來解決承諾的數組:

deferred.map(promiselist).then(/* ... */) 

另外,你可以,如果你在充分利用deferred.map提高組成和同時更換for..in循環:

var result = {}; 
deferred.map(Object.keys(metrics), function (name) { 
    return metrics[name]().aside(function (value) { result[name] = value; }); 
}).done(function (resultArr) { 
    console.log('All metrics loaded', resultArr, result); 
}); 
+0

我很希望在代碼中看到所有的promise對象都是'then'函數。你推薦使用一種語法('.then()'和直接調用)嗎? – Bergi

+0

我把這個決定留給開發者。如果您希望您的代碼看起來像使用通用承諾實現,使用'promise.then()'。如果您覺得使用'promise()'可能會讓代碼讀者感到困惑,並且想要直觀地區分'then'調用,那麼還可以使用'promise.then()'。我個人更願意使用'promise()',因爲它讓我看到更簡潔的代碼和算法邏輯更加透明。這也是一個很好的功能,允許您編寫可以同步或異步功能備份的通用算法。 –