如何打破承诺链?

时间:2017-06-20 15:58:28

标签: javascript jquery promise bluebird chain

  

我知道有类似的问题,但我还没有看到任何解决这种链接模式的问题。

我有以下内容:

    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

我考虑的选项:

  • 提高一些全局标志,以防止从链中进一步执行。哎呀,因为连锁店仍在继续,它只是被清空了。
  • throw new Error(result)代替return result。这会破坏链条(我认为......),但它会误导Error并且很容易被其他开发者误解。

如何在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甚至成功地调用了......但是当我单步执行时,不会调用该拒绝。它好像在我得到结果时,链中的所有链接都已被调用。

2 个答案:

答案 0 :(得分:1)

尝试使用:

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失败了。这实际上会简化你的代码。

答案 1 :(得分:1)

可以使用标志和例外,但正如您所注意到的那样,它们不是正确的工具。

相反,使用递归,就像@ IsiahMeadows'回答,或右折:

SELECT tblRoster.EDIPI, [tblRoster].[LastName] & ", " & [tblRoster].[FirstName] & " " & Left$([tblRoster].[MiddleName],1) AS [Full Name], tblBasicIndividualRecords.PriMilOccSpec AS MOS, DLookUp("LongName","tblMilitaryOccupationalSpecialties","tblMilitaryOccupationalSpecialties!ID = " & [tblBasicIndividualRecords].[PriMilOccSpec]) AS [MOS Decription], DLookUp("Abbreviation","tblRankStructure","tblRankStructure!ID = " & [tblRoster].[Rank]) AS Rank, Format([EndOfActiveService],"yymmdd") AS EAS, tblBasicIndividualRecords.Billet, tblBasicIndividualRecords.OnHand, tblBasicIndividualRecords.Remarks, tblBasicIndividualRecords.Deployable, tblRankStructure.SortValue, tblMilitaryOccupationalSpecialties.SortOrder
FROM tblMilitaryOccupationalSpecialties INNER JOIN ((tblRankStructure INNER JOIN tblRoster ON tblRankStructure.ID = tblRoster.Rank) INNER JOIN tblBasicIndividualRecords ON tblRoster.EDIPI = tblBasicIndividualRecords.EDIPI) ON (tblMilitaryOccupationalSpecialties.ID = tblBasicIndividualRecords.AddMilOccSpec.Value) AND (tblMilitaryOccupationalSpecialties.ID = tblBasicIndividualRecords.PriMilOccSpec)
ORDER BY tblRankStructure.SortValue DESC;

或更好地写为

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));