NodeJS中的一系列承诺延期承诺?

时间:2013-10-12 10:10:21

标签: javascript node.js promise deferred

我想创建一个模块,输出一组关于应用程序运行状况的指标,例如后台队列长度,服务依赖的响应时间等。这是使用Deferred的Node JS:

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正在重复使用每次迭代,所以如果我有多个指标,它可能只跟踪最后一个。

2 个答案:

答案 0 :(得分:1)

我同意Bergi指出的大部分内容。你不应该销毁metrics方法,你应该在其内部创建并返回promises。

您可以做一些其他改进:

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);
});

答案 1 :(得分:0)

metrics[i] = result;

这是一个坏主意。你不应该销毁metrics对象,它的属性应该是并保持功能。如果您想要一个包含结果的对象,请构建一个新对象。

  

延迟退货([承诺数组])(团体承诺)的想法似乎不起作用

the docs和代码可以看出该库不支持数组作为参数。您需要使用apply

deferred.apply(null, promiselist)
  

我刚刚意识到def会在每次迭代中被重用,所以如果我有多个指标,它可能只跟踪最后一个。

不,它没有被重用,你在每个循环转弯时创建一个新的延迟对象。但是你确实忘记了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;
});