【问题标题】:Promise from an array of promises in NodeJS Deferred?来自 NodeJS Deferred 中的一系列承诺的承诺?
【发布时间】:2013-10-13 20:49:45
【问题描述】:

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

【问题讨论】:

    标签: javascript node.js promise deferred


    【解决方案1】:

    我同意 Bergi 指出的大部分内容。你不应该破坏 metrics 方法,你应该在它们内部创建和返回 Promise。

    您还可以做一些其他改进:

    deferred.map(与[].map对应)专用于列表和数组,您可以直接使用它来解析promise数组:

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

    【讨论】:

    • 我很感兴趣地在代码中看到所有的 promise 对象都是 then 函数。您是否建议使用一种语法(.then() 与直接调用)而不是另一种?
    • 我把这个决定留给了开发者。如果您希望您的代码看起来像是用常见的承诺实现编写的,请使用promise.then()。如果你觉得使用promise() 可能会让代码阅读者感到困惑,并且想在视觉上区分then 调用,那么也可以使用promise.then()。我个人更喜欢使用promise(),因为它让我的代码更加简洁,算法逻辑更加透明。它也是一个不错的功能,允许您编写可以由同步或异步函数支持的通用算法。
    【解决方案2】:
    metrics[i] = result;
    

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

    return deferred([array of promises])(group promise) 的想法似乎行不通

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

    【讨论】:

      猜你喜欢
      • 2018-10-03
      • 1970-01-01
      • 2016-09-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-18
      • 1970-01-01
      • 2019-09-29
      相关资源
      最近更新 更多