如何在承诺链中调用Q promise通知

时间:2014-05-26 08:03:42

标签: javascript promise q

我需要帮助链中的notify()

我有3个承诺基函数connect()send(cmd)disconnect()。现在我想编写另一个函数来以下面的方式用进度通知来包装这些调用。

function bombard() {
 return connect()
  .then(function () {
    var cmds = [/*many commands in string*/];
    var promises = _.map(cmds, function (cmd) {
     var deferred = Q.defer();
     deferred.notify(cmd);
     send(cmd).then(function (result) {
      deferred.resovle(result);
     });
     return deferred.promise;
    });
    return Q.all(promises);
  })
 .finally(function () { return disconnect() })
}

运行类似

的功能
bombard.then(onResolve, onReject, function (obj) {
 console.log(ob);
});

我想我会收到我发送的每个命令的通知。但是,它没有像我预期的那样工作。我什么都没得到。

虽然我认为这是因为这些通知已传播到外部承诺,但我不知道如何在Q上传播这些通知或包装该承诺链:connect,{{1} },send在一个延迟对象中。

由于

1 个答案:

答案 0 :(得分:12)

我有一些好消息和一些坏消息。

非常好!您已经发现了通知API的问题以及它在v2分支中被删除的原因,在Bluebird这样的新库中被弃用,并且从未包含在ECMAScript 6中。它实际上归结为promises不是事件发射器

通知API不会很好地组合或聚合。事实上,承诺上的通知开始时并没有太多意义,。

相反,我建议使用进度通知,有点像C#中的IProgress。我将使用Q.delay()模拟所有操作以进行隔离,您的代码显然会进行真正的调用

function connect(iProgress){
    return Q.delay(1000).then(function(res){
        iProgress(0.5,"Connecting to Database");
    }).delay(1000).then(function(res){
        iProgress(0.5,"Done Connecting");
    });

} 

function send(data,iProgress){
     return Q.delay(200*Math.random() + 200).then(function(res){
         iProgress(0.33, "Sent First Element");
     }).delay(200*Math.random() + 400).then(function(){
         iProgress(0.33, "Sent second Element");
     }).delay(200*Math.random() + 500).then(function(){
         iProgress(0.33, "Done sending!");
     });
}
// disconnect is similar

现在,我们可以轻松决定我们的承诺如何构成,例如:

function aggregateProgress(num){
     var total = 0;
     return function(progression,message){
          total += progression;
          console.log("Progressed ", ((total/num)*100).toFixed(2)+"%" );
          console.log("Got message",message);
     }
}

可以让你这样做:

// bombard can accept iProgress itself if it needs to propagate it
function bombard() {
 var notify = aggregateProgress(cmds.length+1);
 return connect(notify)
  .then(function () {
    var cmds = [/*many commands in string*/];
    return Q.all(cmds.map(function(command){ return send(command,notify); }));
  });
}

Here is a complete and working fiddle to play with