如何打破承诺链?

How to break a promise chain?

I'm aware that there are similar questions, but I haven't seen any that address this chaining pattern.

我有以下内容:

    var runTests = function (chain, resolutionTest) {
        return chain.then(function (result) {
            if (result)
                return result; // Early return if the previous tests were successful.  This is where I want to prevent other attempts.
            const attempt = tryOpenStream(resolutionTest).then(streamToDom);
            return attempt;
        });
    }

    // from someplace else
    numTests = resolutionTests.length;
    return resolutionTests.reduce(runTests, Promise.resolve()); // start reduce with an empty promise 

我遇到的问题是我多次调用 tryOpenStream,甚至在我捕获 result 之后也是如此。

我正在考虑的选项:

如何在 return result; 打破这条链?

更新 1

我正在尝试以下操作:

   var makeTest = function (runMoreTests, resolutionTest) {
        return function runTest() {
            return tryOpenStream(resolutionTest).then(streamToDom).then(function (result) {
                if (result)
                    return result;
                else
                    return runMoreTests();
            });
        };
    }

    return resolutionTestBuilder.buildTests().then(function (resolutionTests) {
        numTests = resolutionTests.length;
        return resolutionTests.reduceRight(makeTest, function () { Promise.reject("No resolutions succeeded.") })();
    });

但是没有调用 runTest。这对我来说有点新语法,所以我会研究一些并更新任何发现。

更新 2

我缺少 () 来调用 reduceRight。虽然现在我看到 reject 即使成功也被调用了……但是当我逐步执行时,不会调用拒绝。好像当我得到返回结果时,链中的所有链接都已被调用。

试试这个:

function runTests(resolutionTest) {
    return tryOpenStream(resolutionTest).then(streamToDom)
}

// from someplace else
function loop(tests, i) {
    if (i === tests.length) return undefined
    return runTests(tests[i]).then(function (result) {
        if (result) return result
        return loop(tests, i + 1)
    })
}
return loop(resolutionTests, 0)

尽管我确实想知道为什么您不能使用异常来表示您的 tryOpenStream 失败。这实际上会简化您的代码。

标志和异常都可以使用,但正如您所注意到的,它们不是合适的工具。

相反,使用递归,如@IsiahMeadows 的回答,或正确的折叠:

var makeTest = function (runMoreTests, resolutionTest) {
    return function runTest(result) {
        if (result)
            return result;
        return tryOpenStream(resolutionTest).then(streamToDom).then(runMoreTests);
    };
}

return Promise.resolve(resolutionTests.reduceRight(makeTest, x => x)(undefined));

或更好地写成

var makeTest = function (runMoreTests, resolutionTest) {
    return function runTest() {
        return tryOpenStream(resolutionTest).then(streamToDom).then(result => {
            if (result)
                return result;
            else
                return runMoreTests();
        });
    };
}

return resolutionTests.reduceRight(makeTest, () => Promise.reject("nothing succeeded"))();