有没有一种好的方法来简化JavaScript promises?

6

对于 Promise/Deferred,我还是一个初学者。在处理 Promise 链的过程中,如果想要快速中止链条,不管是成功还是出错的情况下,有没有一个好的模式?在错误情况下,你可以在最后加上 .then(null, function(error) {})来捕获之前所有 then 的错误,但是如果你想以一种更自定义的方式处理错误并终止呢?你会在早期错误处理程序中指定一个错误的“类型”,然后通过新的 Promise 返回它,以便在最终的错误处理程序中进行处理或跳过它吗?而对于成功的情况,如果你想在链条的早期中止(仅在特定条件下触发后续的 then),该怎么办呢?


method.success(function(){}).error(function(){}) 的意思是什么? - Moritz Roessler
4个回答

4

通常,Promise链以对某个异步函数的调用开始,例如:

var promise = callAsync();

如果您正在链接第二个异步调用,您可能会像这样做:
var promise = callAsync()
.then(function(){
    return callOtherAsync();
})
.then(function(){
    return callSuccessAsync();
}, function(){
    return callFailAsync();
});

由于链接操作,现在promise包含了最终的承诺,在callFinalAsync()的承诺完成时它也会完成。使用这种模式没有办法使最终的promise提前结束 - 您可以在一路上返回一个失败的承诺(例如,而不是返回callOtherAsync的结果),但这需要失败的承诺通过链条进展(从而导致调用callFailAsync)。 您始终可以从回调中履行或拒绝promise,如下所示。
var promise = callAsync()
.then(function(){
    if(fail){
        promise.reject();
        //no way to halt progression 
    }else{
        return callOtherAsync();
    }
})
.then(function(){
    return callSuccessAsync();
}, function(){
    return callFailAsync();
});

然而,这并不能阻止对callFailAsync()的调用。一些Promise/A实现会为此暴露一个stop方法。使用stop,你可以这样做:
var promise = callAsync();
.then(function(){
    if(fail){
        this.stop(); 
        promise.reject();
    }else{
        return callOtherAsync();
    }
})
.then(function(){
    return callSuccessAsync();
}, function(){
    return callFailAsync();
});

这取决于是否能够访问中间的 Promise,使用 this。一些 Promise 实现禁止访问(强制将 this 设为 window/null 等),但可以通过闭包来处理。

简而言之,Promise / A 规范没有提供链式短路函数,但添加一个并不难。


3

我不确定jQuery是否支持,但至少在任何Promises/A+规范中,你可以直接抛出错误:

.then(function() {
    if (skip) {
        throw new Error("skipping");
    }
})
//Chain of thens
.then(...)

.then(...)

.then(...)

.then(...)

.catch(function(){
    //skipped here
});

1
我假设你的使用情况如下所示:

promise
.then(a) 
.then(b); // We want to have an option to break here
.then(c)
.done(d)

处理这个问题的逻辑方式是:
promise
.then(a) 
.then(function (result) {
    if (something) throw new Error("Do not proceed!");
    return b(result).then(c).then(d);
}).done();

如果您不喜欢嵌套,可以将b(result).then(c).then(d)组合成外部函数。

1
我在我的应用程序中遇到了这个确切的问题,并通过使用一个简单的取消令牌对象来实现短路/取消,可以在Promise的异常/拒绝处理程序回调中进行检查。也许不是最优雅的解决方案,但似乎足够好地工作,而无需使用其他库或替代/非标准的Promise实现。
const cancellationToken = {};

somePromiseReturningMethod(...)
    .then(doSomething)
    .then(doSomethingElse)
    .catch(err => {
        if (err === cancellationToken)
        {
            // handle cancellation here and return
        }

        // handle "regular" errors here (show/log a message, etc)
    });

function doSomething(dataFromPromise)
{
    // check for whatever condition should result in cancellation/short-circuit
    if (...)
    {
        return Promise.reject(cancellationToken);
    }

    // carry on as normal...
}


1
使用Symbol('cancellation')作为令牌可能比使用空对象更清晰。非常好的解决方案! - Nick Bull

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接