AngularJS - $ q.all()失败弹性

时间:2013-12-13 09:29:15

标签: ajax angularjs promise q

我正在尝试填写解决一系列远程呼叫的本地数据 当每个承诺都得到解决后,我会加载数据并继续。

方法$q.all( [] )正是这样做的:

        $q.all([
            this.getUserInfo(11)
                .then(function (r) {
                    results.push(r)
                }),

            this.getUserConns()
                .then(function (r) {
                    results.push(r)
                }),

            this.getUserCtxs()
                .then(function (r) {
                    results.push(r)
                })
        ])
        .then(function () {
            console.log(results)
        })


问题是,这段代码没有弹性 如果这些呼叫中的任何一个失败,没有人会得到鱼!

在try / catch语句中包装调用只会导致$q.all()完全忽略该条目,即使没有失败(请注意func中的console.log)...

        $q.all([
            this.getUserInfo2(11)
                .then(function (r) {
                    results.push(r)
                }),

            function () {
                try {
                    this.getUserGroups()
                        .then(function (r) {
                            console.log(r)
                            results.push(r)
                        })
                }
                catch (err) {
                    console.log(err)
                }
            },
        ])
        .then(function () {
            console.log(results)
        })

输出:

  
    

[对象]

  


有关我如何将其包裹起来以保持弹性的任何提示?

<小时/> 感谢@dtabuenc,我更进了一步。 实现错误回调,我可以避免链断开,并推送已解决的promises的值。

但是,控制台上仍会显示令人讨厌的异常...... 如果我不能尝试/捕获异步请求,我怎么能摆脱它呢?

来电者代码

    return $q.all([

            this.getUserInfo(user_id)
                .then(function (r) {
                    results['personal_details'] = r
                }),

            this.getUserConns()
                .then(
                    function (r) {
                    results['connections'] = r
                    },
                    function(err) {
                        console.log(err)
                    })

        ])
        .then(function () {
            return (results)
        })

Callee代码(注入异常)

    getUserConns: function() {

        return __doCall( ws.getUserConnections, {} )
            .then( function(r) {

                // very generic exception injected
                throw new Error

                if (r && r.data['return_code'] === 0) {
                    return r.data['entries']
                }
                else {
                    console.log('unable to retrieve the activity - err: '+r.data['return_code'])
                    return null
                }
            })
    },

5 个答案:

答案 0 :(得分:24)

这会起作用,但也会将错误推送到数组。

function push(r) {
    results.push(r);
}

$q.all([
    this.getUserInfo(11).then(push).catch(push),
    this.getUserConns().then(push).catch(push),
    this.getUserCtxs().then(push).catch(push)
])
.then(function () {
    console.log(results);
})

您还应该提高对承诺的理解,从不应该使用try-catch承诺 - 使用承诺时,您使用.catch()方法(其他一切都是隐含的)一个try)。这适用于正常错误和异步错误。


如果您想完全忽略错误:

function push(r) {
    results.push(r);
}

function noop() {}

$q.all([
    this.getUserInfo(11).then(push).catch(noop),
    this.getUserConns().then(push).catch(noop),
    this.getUserCtxs().then(push).catch(noop)
])
.then(function () {
    console.log(results);
})

答案 1 :(得分:2)

我认为这样做更容易:

$q.all([
 mypromise1.$promise.catch(angular.noop),
 mypromise2.$promise.catch(angular.noop),
 mypromise1.$promise.catch(angular.noop)
])
.then(function success(data) {
 //.....
});

答案 2 :(得分:0)

我不确定你的弹性是什么意思。如果其中一个承诺失败,你想要发生什么?

您的try-catch将无法正常工作,因为promise将异步失败。

然而,您可以将错误处理程序作为第二个参数传递给then()调用,并在那里执行任何操作。

答案 3 :(得分:0)

这里的问题相同。对于那些有for循环的人:在一个响应中:

var tracks = [];
var trackDfds = [];
for(var i = 0; i < res.items.length; i++){
    var fn = function () {
        var promise = API.tracks(userId, res.items[i].id);
        return promise.then(function (res) {
            if (res.items.length) {
              tracks.push(res.items);
            }
        }).catch(angular.noop);
    };
    trackDfds.push(fn());
}
$q.all(trackDfds)
    .then(function (res) {
        console.log(tracks);
    });

答案 4 :(得分:0)

@ Esailija的答案似乎是解决问题的方法。 您无法在问题的主要贡献者之外解决问题:$q

对每个then(第二个参数)进行拒绝回调并在其中插入$q.reject(...)似乎更明智一些。

示例:

$q.all([
    this.getUserInfo(11).then(
        function (response) { // UI data preparation for this part of the screen }, 
        function (response) {
           $q.reject(response);
        }
    ),
    // ...
])
.then(
    function () {
      // all good
    },
    function () {
      // at least one failed
    }
)

当UI模型依赖于所有ajax调用时,会特别指出。

我个人认为这是一种安全的继续进行方式,因为大多数时候你确实想要将一些服务器消息推送到拒绝回调上的某个toast组件,或者以某种方式提醒用户(排队7个ajax调用不会这意味着你无法展示任何东西,因为1失败 - 这意味着你将无法显示屏幕的某个区域 - 需要向用户提供专门的反馈。)