【问题标题】:Using Promise.all to wait until all callbacks have completed使用 Promise.all 等待所有回调完成
【发布时间】:2016-10-25 03:33:57
【问题描述】:

我正在尝试发出两个 HTTP 请求来检索数据,每个请求都有一个回调函数。只有两个回调函数都完成后,我才想运行最后一段代码。也许这是我对承诺的不熟悉,但我似乎无法让它发挥作用。我只是让它立即或从不运行最终的 thenable 代码。

var p1 = getStatus(account1, currency, processStatus)
var p2 = getStatus(account2, currency, processStatus)

Promise.all([p1, p2]).then(function() {
    // evaluate complete status
})

getStatus是一个coffeescript函数,它发出一个HTTP请求,一旦检索到数据,它就会调用提供的回调函数,也就是第三个参数。

getStatus: (acctId, curr, callback) =>
    options = {url: url, account: acctId, currency: curr}
    new Promise => request options, (err, resp, body) =>
        if !err
            return Promise.resolve callback(null, acctId, curr, JSON.parse(body))

processStatus 是一个 JavaScript 函数,用于处理检索到的数据。

module.exports.processStatus = function(err, acctId, curr, status) {
    status.forEach(function(s) {
        // ....
    })
    return Promise.resolve(true)
})

如何更改此设置以使 evaluate complete status 代码仅在 两个 processStatus 回调完成后执行?

【问题讨论】:

  • 您的processStatus 似乎不是异步的。为什么它会返回一个承诺?
  • 我认为它需要返回一个承诺,因为它是 getStatus 的回调函数。我看不到让 Promise.all() 等到两个回调完成的另一种方法。即使 processStatus 没有返回承诺,您下面的答案是否有效?
  • 不,getStatus的promise和它的callback参数没有任何关系。是的,我的回答适用于任何返回任何内容的回调函数。

标签: javascript node.js callback coffeescript bluebird


【解决方案1】:

您似乎将静态Promise.resolve method 与传递给new Promise 构造函数的执行程序回调的resolve function 混淆了。正确的是

getStatus: (acctId, curr, callback) =>
    options = {url: url, account: acctId, currency: curr}
    new Promise (resolve, reject) => request options, (err, resp, body) =>
#               ^^^^^^^^^^^^^^^^^
        if !err
            resolve callback(null, acctId, curr, JSON.parse(body))
        else
            reject err

但实际上更好的是

getStatus: (acctId, curr, callback) =>
    options = {url: url, account: acctId, currency: curr}
    new Promise (resolve, reject) =>
        request options, (err, resp, body) =>
            if !err
                resolve body
            else
                reject err
    .then JSON.parse
    .then (status) => callback null, acctId, curr, status

【讨论】:

  • 第二个代码块的倒数第二行是否缺少某些内容? JSON.parse 的结果如何在变量 status 中结束?
  • @greymatter:什么都没有。 JSON.parse 在这里直接用作回调。 It's magic!(呃,我是说,一个函子)
【解决方案2】:

尝试使用反射。参考伪代码。

    // Extend the ability of promise.all() to wait until all promises are resolved/rejected before returning.
    // By default, promise.all() will return if any 1 of the promise pass or fails.
    var reflect = function reflect(promise){
        return promise.then(function(/*resolve return value=*/v){ return { v:v, status: "resolved" }},
            function(/*rejection error=*/e){ return { e:e, status: "rejected" }});
    };


    var promises = [
        new Promise(function(resolve, reject) {
            resolve();
        }),
        new Promise(function(resolve, reject) {
            resolve();
        })
    ];

    Promise.all(promises.map(reflect)).done(function() { resolve(); });

【讨论】:

  • promises 的声明包含语法错误,似乎没有任何意义
  • 注意:这只是伪代码。主要思想是关于反映而不是承诺。
  • @Bergi 我已经重构了承诺部分。现在应该更有意义了。感谢您再次指出。为混乱道歉。
  • 从我在bluebirdjs.com/docs/api/promise.all.html 看到的情况来看,您所说的对于reject 案例来说似乎是准确的,但对于resolve 案例来说并不准确(都必须通过)。我是不是误会了?不管怎样,谢谢你让我知道反射()。
  • @greymatter 我刚刚做了一个实验,你是对的。所以我在这里的建议对于这种情况是无效的。请随意投反对票。仅当无论如何都想等待所有承诺完成时才应使用反射。也就是说,即使遇到错误,它仍然会等待其他承诺。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-19
  • 1970-01-01
  • 2019-06-11
  • 2016-03-16
  • 2016-03-09
  • 2016-02-17
相关资源
最近更新 更多