如何打破承诺链

时间:2015-03-02 05:36:35

标签: javascript selenium-webdriver promise selenium-chromedriver

我是这样的承诺,

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会返回一个承诺,是checkIf 无法修改

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

7 个答案:

答案 0 :(得分:3)

我会使用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
}

如果你没有发电机,那么它总是跟踪或6to5。

答案 1 :(得分:3)

我想你不想要链条。以同步的方式,你已经写了

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

这就是它应该如何转化为承诺:

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 else - 扁平化。

答案 2 :(得分:3)

你可以使用 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中获取结果。 当时能够"然后"接受回调但在这种情况下永远不会被调用。所以"然后()"返回,并且链的其余部分的回调不会发生。

答案 3 :(得分:1)

您可以创建一个firstSucceeding函数,该函数将返回第一个成功操作的值或抛出NonSucceedingError

我已经使用过ES6承诺,但您可以调整算法以支持您选择的承诺界面。



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




答案 4 :(得分:0)

我喜欢到目前为止发布的很多答案,可以缓解q readme所谓的“厄运金字塔”。为了便于讨论,我将添加我在搜索周围以查看其他人正在做什么之前插入的模式。我写了一个像

这样的函数
var null_wrap = function (fn) {
  return function () {
    var i;
    for (i = 0; i < arguments.length; i += 1) {
      if (arguments[i] === null) {
        return null;
      }
    }
    return fn.apply(null, arguments);
  };
};

我做了一些与@ vilicvane的答案完全类似的事情,除了throw new BreakSignal()之外,我写了return null,并将所有后续的.then回调包裹在null_wrap

then(null_wrap(function (res) { /* do things */ }))

我认为这是一个很好的答案b / c它避免了很多缩进和b / c OP特别要求的解决方案不是throw。那说,我可以回去使用更像@vilicvane做的事情b / c一些图书馆的承诺可能会返回null来表示除了“打破链条”以外的东西,这可能会令人困惑。

这更像是要求获得更多评论/答案,而不是“这绝对是做到这一点的方式”。

答案 5 :(得分:0)

可能会来晚会,但我最近发布了一个使用生成器和co库来回答这个问题的答案(见解决方案2):

代码如下:

const requestHandler = function*() {

        const survey = yield Survey.findOne({
            _id: "bananasId"
        });

        if (survey !== null) {
            console.log("use HTTP PUT instead!");
            return;
        }

        try {
            //saving empty object for demonstration purposes
            yield(new Survey({}).save());
            console.log("Saved Successfully !");
            return;
        }
        catch (error) {
            console.log(`Failed to save with error:  ${error}`);
            return;
        }

    };

    co(requestHandler)
        .then(() => {
            console.log("finished!");
        })
        .catch(console.log);

您几乎可以编写实际上异步的同步代码!

希望它有所帮助!

答案 6 :(得分:0)

尝试使用像这样的库:

https://www.npmjs.com/package/promise-chain-break

    db.getData()
.then(pb((data) => {
    if (!data.someCheck()) {
        tellSomeone();

        // All other '.then' calls will be skiped
        return pb.BREAK;
    }
}))
.then(pb(() => {
}))
.then(pb(() => {
}))
.catch((error) => {
    console.error(error);
});