JavaScriptBluebird承诺:并发API请求的体系结构

JavaScriptBluebird承诺:并发API请求的体系结构,javascript,promise,bluebird,Javascript,Promise,Bluebird,我正在寻求建筑方面的建议。在一个普通的环境中使用Bluebird Promises(这里是node.js服务器端),我打算进行许多并发API调用,聚合所有结果并响应客户端。示例(伪)代码: 现在我不知道如何确保: 同时激发所有请求(不是按顺序以减少 响应时间) 收到所有API请求的响应后立即响应客户端 如果一个API请求因任何原因而失败,则不会拒绝整个承诺链,从而“丢失”另一个API响应数据 我在Bluebird Promise网站上查看了合适的收藏,但似乎没有一个完全符合上面列出的要求。有什么

我正在寻求建筑方面的建议。在一个普通的环境中使用Bluebird Promises(这里是node.js服务器端),我打算进行许多并发API调用,聚合所有结果并响应客户端。示例(伪)代码:

现在我不知道如何确保:

  • 同时激发所有请求(不是按顺序以减少 响应时间)
  • 收到所有API请求的响应后立即响应客户端
  • 如果一个API请求因任何原因而失败,则不会拒绝整个承诺链,从而“丢失”另一个API响应数据

  • 我在Bluebird Promise网站上查看了合适的收藏,但似乎没有一个完全符合上面列出的要求。有什么建议吗?

    一种方法是使用
    reflect
    调用

    var Promise= require('bluebird');
    
    Promise.props({
      "wrapper1": someasync(1).reflect(),
      "wrapper2": someasync(0).reflect(),
      "wrapper3": someasync(1).reflect()
    })
    .then(function(results) {
      Object.keys(results).forEach(function(key) {
        if (results[key].isRejected()) {
          console.log(key + " failed.", results[key].reason());
        } else {
          console.log(key + " successed", results[key].value());
        }
      });
    });
    
    function someasync(t) {
      if (t===0) return Promise.reject('some err');
      else return Promise.resolve(true);
    }
    
    其结果如下:

    wrapper1 successed true
    wrapper2 failed. some err
    wrapper3 successed true
    

    如果需要,可以手动推荐API方法,例如:

    var p1 = new Promise(function(resolve, reject) {
      wrapper1.getResultsFromAPI1(searchquery, function(err, data) {
        if (err) reject(err);
        else resove(data);
      });
    });
    
    但是既然您使用的是BlueBird库,那么就可以使用
    promisify.promisify
    ,这样就可以避免将方法包装成promises的样板代码。例如:

    var getResultsFromAPI = Promise.promisify(wrapper1.getResultsFromAPI1);
    var p1 = getResultsFromAPI(searchquery);
    
    而且,如果您想推广API的所有方法,可以使用
    Promise.promisifyAll
    。例如:

    var wrapper1 = Promise.promisifyAll(require('my-api'));
    
    // then, all the wrapper1 methods are already wrapped into a Promise
    var p1 = wrapper1.getResultsFromAPI1(searchquery);
    
    因此,在将所有方法转化为承诺后,您可以使用
    承诺。解决
    来实现您想要的:查看哪些承诺得到了履行,哪些承诺被拒绝:

    exports.getAllData = function(searchquery, cb) {
      /* Don't forget to promisify all the API methods firstly */
    
      var results;
    
      var p1 = wrapper1.getResultsFromAPI1(searchquery);
      var p2 = wrapper2.getResultsFromAPI2(searchquery);
      var p3 = wrapper3.getResultsFromDataBase(searchquery);
    
      Promise.settle([p1, p2, p3]).then(function(arr) {
        arr.forEach(function(res, index) {
          if (res.isFulfilled()) {     // check if the Promise was fulfilled
            results += res.value();    // the Promise's return value
          }
          else if (res.isRejected()) { // check if the Promise was rejected
            console.log(res.reason()); // do something with the error
          }
        });
    
        cb(null, results);
      });
    }
    

    承诺。结算
    应该可以。如果我错了,请纠正我,但结算仅在承诺数组中的所有项都已结算后才进行结算。一旦有一项(在我的例子中是一个API调用)失败,整个承诺链就会失败。这不是我需要的。@IgorP<代码>承诺。当传递的承诺之一失败时,所有
    都将失败<代码>承诺。结算
    将为您提供一个数组,其中包含拒绝承诺和解决承诺的信息。因此,您将解决您的
    问题,看看是否所有请求都已完成。哦,好的。我当时一定是误解了网上的参考资料。我试试看。谢谢=)@Bergi请给我一个评论
    
    var wrapper1 = Promise.promisifyAll(require('my-api'));
    
    // then, all the wrapper1 methods are already wrapped into a Promise
    var p1 = wrapper1.getResultsFromAPI1(searchquery);
    
    exports.getAllData = function(searchquery, cb) {
      /* Don't forget to promisify all the API methods firstly */
    
      var results;
    
      var p1 = wrapper1.getResultsFromAPI1(searchquery);
      var p2 = wrapper2.getResultsFromAPI2(searchquery);
      var p3 = wrapper3.getResultsFromDataBase(searchquery);
    
      Promise.settle([p1, p2, p3]).then(function(arr) {
        arr.forEach(function(res, index) {
          if (res.isFulfilled()) {     // check if the Promise was fulfilled
            results += res.value();    // the Promise's return value
          }
          else if (res.isRejected()) { // check if the Promise was rejected
            console.log(res.reason()); // do something with the error
          }
        });
    
        cb(null, results);
      });
    }