【问题标题】:Sequentially running Q Promises顺序运行 Q Promises
【发布时间】:2015-09-22 21:17:11
【问题描述】:

Node.js 应用程序中,我想实现这一点: 读取数组,取决于项目类型,决定使用返回 Q Promise 对象的特定函数。我希望这个过程按顺序运行。

我有这两个承诺:

var q = require('q');
Classes.prototype.fn1 = function (item) {
    return q.Promise(function(resolve, reject){
        Items.find({item_published: true}).exec(
            function (err, events) {
                if (err) {
                    reject('an error happened');
                    throw err;
                }else{
                    resolve(events);
                }
        });
    });
};

Classes.prototype.fn2 = function (item) {
    return q.Promise(function(resolve, reject){
        resolve(item);
    });
};

这是主要代码:

self.items = [{},{},{}]; //some items
self.result = [];

self.items.forEach(function(item,index,array){

    if(item.type == 1){
        self.fn1(item)
            .then(function(result){
                self.result.push(result);
        })
    }

    if(item.type == 2){
        self.fn2(item)
            .then(function(result){
                self.result.push(result);
        })
    }

    if(index == array.length-1){
        callback(self.result);
     }
});

但它不起作用。因为fn1 有一个异步进程,所以它在fn2 之后运行。我想要的只是顺序运行这些函数,即使其中一个具有异步进程。

【问题讨论】:

  • 不要拒绝扔,只是拒绝。
  • 你为什么不直接链接承诺?您也可以将if 语句放在then 方法中。
  • @TheMinister:我尝试了很多方法,但最后,由于 fn1 的异步行为,没有遵循顺序。你能给我一个你所说的真实例子吗?这两天我无法解决这个问题。谢谢

标签: javascript node.js promise q


【解决方案1】:

您可以使用.reduce 链接承诺。

var promise = q(); // Create a Resolved promise for chaining.
self.items = [{},{},{}]; //some items
self.result = [];

// We put an resolved promise as init value for chaining
self.items.reduce(function(chain, item) {
    // Don't do anything if item type is not match
    if (item.type !== 1 && item.type !== 2) {
      return chain;
    }

    var targetFunc = null;
    if (item.type === 1) {
      targetFunc = self.fn1;
    } else if (item.type === 2) {
      targetFunc = self.fn2;
    }

    if (targetFunc === null) {
      return chain;
    }

    // Chain the promise and return the last of the chain.
    return chain
      .then(function(){
        return targetFunc(item);
      })
      .then(function(result){
        // This then will get the result from above
        // so we put the result to self.result here
        self.result.push(result);
      });
}, promise).then(function() {
  // When all promises are sequentially resolved,
  // call the callback with self.resul.
  callback(self.result);
});

jsfiddle, jsfiddle-Q.js ver.

【讨论】:

  • Reduce 需要一个返回值。目前var chained 什么都不做。应该是return chain.then(…)
  • 啊,我把 return 改成 var 是出于某种忘记的目的,但也忘了返回,非常感谢。
  • @fuyushimoya:一切正常,但最后,self.result 包含我想要的重复值。事实上,我想要两个结果,但不止两个。你能再检查一遍吗?
  • 您是否在self.items 中输入了两个以上的值?与您的原始帖子一样,它包含 3 个项目。或者会有 item.type 不是 1 或 2 而你不想处理它们。
  • @fuyushimoya:如果我有两个项目,self.result.push(result);叫了4次!但为什么呢?
【解决方案2】:

有一些非常类似于下面的烹饪......但是 fuyushimoya 太快了,虽然我们处理 reduce 的初始化不同

var promises = self.items.map( function(item) {
    if (item.type == 2) {
      return self.fn1(item);
    }
    else if (item.type == 3) {
      return self.fn2(item);
    }
 });

function handler(p) {
  return p.then( function(res) {
    self.result.push(res);
  });
}

promises
 .reduce( function(prev, current) {
  if (prev) {
    return prev.then( function() { handler(current) } )
  } 
  else {
    return handler(current)
  }
})
 .then(function(result) {
    callback(null, result);
  })
  .catch( // error handler);

【讨论】:

    【解决方案3】:

    画出来。但这样的事情可能会奏效。

    UPD:诀窍是链接承诺,正如 cmets 中提到的那样,我用于 code snippet here 的更新版本:

     var items = [{type:1},{type:2},{type:1}];
     var result = [];
     var rq = Q();
     var ql = rq;
    
     items.forEach(function (it, ix) {
    
        ql = ql.then(function(){
          var dp = "fn" + it.type;
          return ps[dp]();
        })
        .then(function(d) {
          result.push(d);
        });
     });
    
    ql.then(function() {
      callback(result);
    });
    

    【讨论】:

    • 您的解决方案非常紧凑,看起来很合理,但它不起作用。我不知道为什么。你能再检查一遍吗?
    • 一切正常,但回调(self.result);返回 [ ]
    • 我找到了原因,最后一个 master.then(function() 在 inner then 之前运行,将数据推送到数组
    • 可能需要常规循环而不是 forEach。让我放真正的代码示例并运行它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-03
    • 2015-06-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多