【问题标题】:Returning a new promise reinforced with backup promises返回一个新的承诺,加强了备用承诺
【发布时间】:2026-01-09 14:35:02
【问题描述】:

我对 Promise 不熟悉,所以我可能遗漏了一些明显的东西。我想要一个函数,它将“承诺创建者”列表作为参数并返回一个承诺,该承诺要么解析为列表中的第一个成功承诺,要么拒绝一些通用错误。这将用于从我有多种后备方法的网站加载数据,以防一个或多个方法失败。

这是我的意思的一个工作示例。有 3 个 promise,m1m2m3,要么成功要么失败。 tryAll 将尝试每一个,直到其中一个(在本例中为 m3)解决,然后将其传递给初始承诺请求的 then 语句。如果要解析m2 而不是m3,则永远不会尝试m3

function m1(){
    return new Promise(function(resolve, reject){
        reject(new Error("Failed 1"));
    });
}

function m2(){
    return new Promise(function(resolve, reject){
        reject(new Error("Failed 2"));
    });
}

function m3(){
    return new Promise(function(resolve, reject){
        resolve("Succeeded 3");
    });
}

function tryAll(methods){
    return new Promise(function(resolve, reject){
        if(methods.length == 0){
            reject(new Error("None worked"));
        }else{
            methods[0]()
                .then(function(data){
                    resolve(data);
                })

                .catch(function(err){
                    methods.shift(); // discard the first since it was already tested
                    tryAll(methods)
                        .then(function(data){
                            resolve(data);
                        })

                        .catch(function(err){
                            reject(err);
                        })
                })
        }
    });
}

tryAll([m1, m2, m3])
    .then(function(data){
        console.log(data);
    })

    .catch(function(err){
        console.log("failed");
    })

有什么方法可以简化tryAll?或者有什么内置的方法可以让我完成同样的事情?

【问题讨论】:

    标签: javascript promise


    【解决方案1】:

    你可以只使用链接而不是返回一个新的承诺。例如:

    function tryAll(methods) {
      if (methods.length === 0) {
        return Promise.reject('None worked');
      }
      return methods[0]().catch(err => tryAll(methods.slice(1)));
    }
    

    tryAll 返回的 Promise 可以是方法 [0] 中的已解析值,或者递归 tryAll 调用的已解析值,或者最终用尽方法的 tryAll 递归的拒绝。

    为了也以迭代方式演示这一点,您可以执行以下操作:

    function tryAll(methods) {
      return methods.reduce((promise,method) => promise.catch(err => method()), Promise.reject('No methods supplied'));
    }
    

    这也将返回相同的承诺链(尽管在这种情况下,如果没有失败,它实际上会拒绝最后一个方法错误)

    【讨论】:

    • 我确实必须将 methods[0] 更改为 methods[0](),但这明显更好。