如何打破Promise链

IT技术 javascript selenium-webdriver promise selenium-chromedriver
2021-01-31 15:36:09

我以这样的方式许下诺言,

function getMode(){
    var deferred = Promise.defer();

    checkIf('A')
    .then(function(bool){
        if(bool){
            deferred.resolve('A');
        }else{
            return checkIf('B');
        }
    }).then(function(bool){
        if(bool){
            deferred.resolve('B');
        }else{
            return checkIf('C');
        }
    }).then(function(bool){
        if(bool){
            deferred.resolve('C');
        }else{
            deferred.reject();
        }
    });

    return deferred.promise;
}

checkIf返回一个 promise,并且 yescheckIf 不能被修改

如何在第一场比赛中跳出锁链?(除了明确抛出错误之外的任何其他方式?)

6个回答

除了显式抛出错误之外还有其他方法吗?

你可能需要抛出一些东西,但它不一定是一个错误。

大多数 Promise 实现都有方法catch接受第一个参数作为错误类型(但不是全部,也不是 ES6 Promise),在这种情况下会很有帮助:

function BreakSignal() { }

getPromise()
    .then(function () {
        throw new BreakSignal();
    })
    .then(function () {
        // Something to skip.
    })
    .catch(BreakSignal, function () { })
    .then(function () {
        // Continue with other works.
    });

我在我自己的 Promise 库的最近实现中添加了中断功能。如果您正在使用ThenFail(您可能不会这样做),您可以编写如下内容:

getPromise()
    .then(function () {
        Promise.break;
    })
    .then(function () {
        // Something to skip.
    })
    .enclose()
    .then(function () {
        // Continue with other works.
    });

您可以使用 return { then: function() {} };

.then(function(bool){
    if(bool){
        deferred.resolve('A');
        return { then: function() {} }; // end/break the chain
    }else{
        return checkIf('B');
    }
})

return 语句返回一个“then-able”,只是 then 方法什么都不做。当从 then() 中的函数返回时, then() 将尝试从 thenable 中获取结果。then-able 的“then”接受一个回调,但在这种情况下永远不会被调用。因此“then()”返回,并且不会发生链其余部分的回调。

谢谢,这在我的情况下有效,而其他人没有申请或没有工作!
2021-04-05 15:36:09

我想你不想要链条在这里。以同步方式,你会写

function getMode(){
    if (checkIf('A')) {
        return 'A';
    } else {
        if (checkIf('B')) {
            return 'B';
        } else {
            if (checkIf('C')) {
                return 'C';
            } else {
                throw new Error();
            }
        }
    }
}

这就是它应该如何转化为Promise的方式:

function getMode(){
    checkIf('A').then(function(bool) {
        if (bool)
            return 'A';
        return checkIf('B').then(function(bool) {
            if (bool)
                return 'B';
            return checkIf('C').then(function(bool) {
                if (bool)
                    return 'C';
                throw new Error();
            });
        });
    });
}

if elsePromise中没有扁平化。

@KenBerkeley:then包括else包括then. 请建议如何压扁它?不,then在 athen内绝对不是Promise反模式。你一定不要忘记returnPromise(一如既往)。
2021-03-13 15:36:09
自动模式之一: then 包括 then
2021-03-20 15:36:09
@Bergi,这不是您的经典.catch()连锁店的候选人吗?
2021-03-29 15:36:09
@robe007 并发执行看起来不错,但是这个问题的 OP 想要一些不同的东西:checkIf()s 应该按顺序制作,并且checkIf('B')应该只A在失败时调用
2021-04-02 15:36:09
@robe007 我说永远不要在new Promise构造函数中嵌套 thenables,也不要不必要地嵌套then调用当您可以简单地将一个 promise 和另一个在外部链接起来时,这很棒,并且如果您的代码在扁平化后仍然可以工作,那么您应该这样做。但情况并非总是如此,例如当内部回调想要关闭变量时,或者当您想要有条件地运行部分异步代码时。Promise 如此强大是因为它们仍然允许这种 monadic 风格。returnthen
2021-04-04 15:36:09

我只会使用coroutines/spawns,这会导致简单的代码:

function* getMode(){
    if(yield checkIf('A'))
        return 'A';
    if(yield checkIf('B'))
        return 'B';
    if(yield checkIf('C'))
        return 'C';
    throw undefined; // don't actually throw or reject with non `Error`s in production
}

如果您没有生成器,那么总会有 traceur 或 6to5。

@BenjaminGruenbaum 是的,这很糟糕,但我试图保留 OP 的代码。null 没有多大意义,你是对的,我现在已经修复了。
2021-03-13 15:36:09
等不及所有主流浏览器都支持生成器了。
2021-04-01 15:36:09
你为什么要扔nullo_0?
2021-04-02 15:36:09
@simonzack 所以return Promise.reject()或者throw undefined如果你必须(两者都不好:P)但为什么抛出null?
2021-04-03 15:36:09
@BenjaminGruenbaum OP 被undefined.
2021-04-12 15:36:09

您可以创建一个firstSucceeding函数,函数要么返回第一个成功操作的值,要么抛出一个NonSucceedingError.

我使用过 ES6 Promise,但您可以调整算法以支持您选择的Promise接口。

function checkIf(val) {
    console.log('checkIf called with', val);
    return new Promise(function (resolve, reject) {
        setTimeout(resolve.bind(null, [val, val === 'B']), 0);
    });
}

var firstSucceeding = (function () {
    
    return function (alternatives, succeeded) {
        var failedPromise = Promise.reject(NoneSucceededError());  
        return (alternatives || []).reduce(function (promise, alternative) {
            return promise.then(function (result) {
                    if (succeeded(result)) return result;
                    else return alternative();
                }, alternative);
        }, failedPromise).then(function (result) {
            if (!succeeded(result)) throw NoneSucceededError();
            return result;
        });
     }
    
    function NoneSucceededError() {
        var error = new Error('None succeeded');
        error.name = 'NoneSucceededError';
        return error;
    }
})();

function getMode() {
    return firstSucceeding([
        checkIf.bind(null, 'A'),
        checkIf.bind(null, 'B'),
        checkIf.bind(null, 'C')
    ], function (result) {
        return result[1] === true;
    });
}

getMode().then(function (result) {
    console.log('res', result);
}, function (err) { console.log('err', err); });

不是downvoter - 但它无缘无故地使用延迟反模式 - 传递延迟并在Promise.defer()这里使用有点毫无意义
2021-03-14 15:36:09
@BenjaminGruenbaum 是的,我最初是这么想的,但担心即使第一次操作成功,也必须进行额外的无用函数调用,直到到达链末端。一个成功的结果将必须遍历具有该设计的整个链。我想这没什么大不了的。另外,我认为您的实现需要特别注意最后一个Promise的结果,不是吗?无论如何,我更新了我的答案,这样更好吗?
2021-03-28 15:36:09
@downvoter,你介意说明这种方法有什么问题吗?
2021-03-30 15:36:09
@BenjaminGruenbaum 你能稍微扩展一下吗?您如何允许getMode返回一个Promise,该Promise仅在众多异步替代方案中的一个满足成功条件时才会解决,而无需创建额外的Promise?
2021-04-08 15:36:09
我会使用then链接。
2021-04-09 15:36:09