Angular - 在promise链的第一个函数中处理$ q中的异常

时间:2014-04-27 14:52:40

标签: javascript angularjs promise

请考虑以下代码:

// Fiddle - http://jsfiddle.net/EFpn8/3/
f1().then(function(data) {
                console.log("success 1: "+data)
                return f2();
            })
            .then(function(data) {console.log("success 2: "+data)})
            .catch(function(data) {console.log("error: "+data)});

function f1() {
    var deferred = $q.defer();
    // An exception thrown here is not caught in catch
    // throw "err";
    deferred.resolve("done f1");        
    return deferred.promise;
}

function f2() {
    var deferred = $q.defer();
    // An exception thrown here is handled properly
    // throw "err";
    deferred.resolve("done f2");        
    return deferred.promise;
}    

如果以下代码在 f2 中运行,但会正确调用 catch 函数。但是,如果 f1 中存在异常,则 catch 代码永远不会执行,只会发生标准JS异常。

在原始Q库中,这可以通过以下代码处理:

    // Fiddle - http://jsfiddle.net/FEPc7/
    Q.fcall(f1).then(function(data) {
        console.log("success 1: "+data)
        return f2();
    })
    .then(function(data) {console.log("success 2: "+data)})
    .catch(function(data) {console.log("error: "+data)});

使用 fcall 可以安全地保护f1功能,并且其中的例外将按预期触发 catch 功能。

由于似乎承诺链的所有成员的相同行为对开发人员来说是有用和自然的,我为AngularJS创建了以下函数:

// Fiddle - http://jsfiddle.net/EFpn8/5/
function promise(work) {
    var deferred = $q.defer();
    try {
        deferred.resolve(work());
    } catch(err) {
        deferred.reject(err);
        throw err;
    }
    return deferred.promise;        
}

可以这样使用:

promise(f1).then(function(data) {
                console.log("success 1: "+data)
                return f2();
            })
            .then(function(data) {console.log("success 2: "+data)})
            .catch(function(data) {console.log("error: "+data)});

这很好,但是,这似乎是一个黑客。在Angular中有继承的东西吗?或者由于某种原因它是不必要的?

2 个答案:

答案 0 :(得分:1)

链的第一次调用是同步的,所以乍一看,将其中引发的异常传递给$q然后调用错误回调,这是异步承诺拒绝(或者确实例外)

引用$q docs

  

Q比$ q还有更多功能

因此缺少fCall功能听起来像团队决定可以删除的东西之一。看起来你必须像你一样自己滚动。您可能希望使用https://gist.github.com/leon/8800809之类的技术来使用$q方法来装饰fCall,因此您可以像以下一样使用它:

$q.fCall(f1).then(function()...

答案 1 :(得分:1)

我知道这是一个较老的问题,但我今天遇到了同样的问题并找到了答案,但我认为我不应该添加fCall()来实现这一点。 经过一番挖掘后,我发现今天可以在Angular v1.5中完成(不知道这在什么时候变得有效):

$q.when().then(() => f1)...