0

我想制作一个模块,输出一组关于我的应用程序运行状况的指标,例如后台队列长度、对服务依赖项的响应时间等。这是使用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在每次迭代中都会被重用,所以如果我有多个指标,它可能只会跟踪最后一个。
4

2 回答 2

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);
});
于 2013-10-13T10:51:11.897 回答
0
metrics[i] = result;

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

return deferred([array of promises])(group promise) 的想法似乎不起作用

文档和代码中,您可以看到该库不支持将数组作为参数。您将需要使用apply

deferred.apply(null, promiselist)

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

不,它没有被重用,您在每个循环转弯时创建一个新的延迟对象。但是,您确实忘记了使变量成为本地变量的var关键字。

变量还有一个问题i——它不在每个 Promise 回调的闭包范围内,这意味着当回调被解析时,变量将已经具有上一次循环的值。检查循环内的 JavaScript 闭包——简单实用的示例

一个小的设计缺陷是这些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;
});
于 2013-10-12T13:27:16.930 回答