AngularJS - $q.all()上的故障抵抗

时间:2022-10-17 00:19:47

I'm trying to fill some local data resolving a series of remote calls.
When every promise is resolved, I load the data and proceed.

我正在尝试填充一些本地数据来解析一系列远程调用。当每个承诺都得到解决时,我将加载数据并继续。

The method $q.all( [] ) does exactly this:

问美元的方法。所有([])就是这样:

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


Problem is, this code is not resilient.
If any of these call fails, nobody gets the fish!

问题是,这段代码没有弹性。如果其中任何一个调用失败了,没有人会得到那条鱼!

Wrapping the calls in a try/catch statement, simply causes $q.all() to entirely ignore the entry, even when not failing (note the console.log in the func)...

在try/catch语句中包装调用,只会导致$q.all()完全忽略条目,即使没有失败(请注意控制台)。登录函数)……

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

Output:

输出:

[Object]

(对象)


Any hint on how I could wrap this to be resilient?

有任何关于如何使它具有弹性的提示吗?


Thanks to @dtabuenc, I've gone one step further. Implementing the error callback, I can avoid the breaking of the chain, and push the values of the resolved promises.

However, a nasty Exception is still displayed on the console... How can I get rid of that if I cannot try/catch on async requests?

然而,控制台仍然显示了一个令人讨厌的异常……如果我不能尝试/捕获异步请求,我如何摆脱它?

Caller code

调用者的代码

    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 code (inject with an exception)

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 个解决方案

#1


23  

This will work but also push the errors to the array.

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

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

You should also improve your understanding of promises, you never should use try-catch with promises - when using promises, you use the .catch() method (with everything else being implicitly a try). This works for normal errors as well as asynchronous errors.

您还应该改进您对承诺的理解,您不应该使用try-catch和promise——在使用promise时,您应该使用.catch()方法(其他方法都是隐式尝试)。这适用于正常的错误和异步错误。


If you want to totally ignore the errors:

如果你想完全忽略这些错误:

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

#2


1  

I think it's easier to do :

我认为这样做比较容易:

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

#3


0  

I'm not sure what you mean by resilient. What do you want to happen if one of the promises fails?

我不知道你说的适应力是什么意思。如果其中一个承诺失败了,你希望发生什么?

Your try-catch won't work because the promise will fail asynchronously.

您的try-catch不能工作,因为承诺将异步失败。

You can however pass in an error handler as the second parameter to the then() call and do whatever you wish there.

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

#4


0  

Same issue here. For those of you with for loops: inside a then response:

同样的问题在这里。对于那些有循环的人:在一个然后回应:

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

#5


0  

@Esailija's answer seems like a workaround to a problem. You can't resolve the problem outside the main contributor to the problem: $q.

@Esailija的回答似乎是一个解决问题的方法。你无法解决问题的主要贡献者之外的问题:$q。

It seems a bit wiser to have reject callbacks for each then (2nd argument) and in there to insert $q.reject(...).

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

Example:

例子:

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

This is particularly indicated when the UI model depends on all ajax calls.

当UI模型依赖于所有ajax调用时,这一点尤为明显。

Personally I think this is the safe way to proceed anyway, because most of the times you do want to push some server messages to some toast component on the reject callbacks, or alert the user in some way (queuing 7 ajax calls doesn't mean you can't show anything because 1 failed - it means you won't be able to show some region of the screen - that needs a specialized feedback to the user).

我个人认为这是安全的方式进行,因为大多数时候你想把一些服务器消息一些吐司组件拒绝回调,或提醒用户以某种方式(排队7 ajax调用并不意味着你不能显示任何东西因为1失败——这意味着你将无法显示屏幕的一些地区,需要一个专门的反馈给用户)。

#1


23  

This will work but also push the errors to the array.

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

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

You should also improve your understanding of promises, you never should use try-catch with promises - when using promises, you use the .catch() method (with everything else being implicitly a try). This works for normal errors as well as asynchronous errors.

您还应该改进您对承诺的理解,您不应该使用try-catch和promise——在使用promise时,您应该使用.catch()方法(其他方法都是隐式尝试)。这适用于正常的错误和异步错误。


If you want to totally ignore the errors:

如果你想完全忽略这些错误:

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

#2


1  

I think it's easier to do :

我认为这样做比较容易:

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

#3


0  

I'm not sure what you mean by resilient. What do you want to happen if one of the promises fails?

我不知道你说的适应力是什么意思。如果其中一个承诺失败了,你希望发生什么?

Your try-catch won't work because the promise will fail asynchronously.

您的try-catch不能工作,因为承诺将异步失败。

You can however pass in an error handler as the second parameter to the then() call and do whatever you wish there.

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

#4


0  

Same issue here. For those of you with for loops: inside a then response:

同样的问题在这里。对于那些有循环的人:在一个然后回应:

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

#5


0  

@Esailija's answer seems like a workaround to a problem. You can't resolve the problem outside the main contributor to the problem: $q.

@Esailija的回答似乎是一个解决问题的方法。你无法解决问题的主要贡献者之外的问题:$q。

It seems a bit wiser to have reject callbacks for each then (2nd argument) and in there to insert $q.reject(...).

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

Example:

例子:

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

This is particularly indicated when the UI model depends on all ajax calls.

当UI模型依赖于所有ajax调用时,这一点尤为明显。

Personally I think this is the safe way to proceed anyway, because most of the times you do want to push some server messages to some toast component on the reject callbacks, or alert the user in some way (queuing 7 ajax calls doesn't mean you can't show anything because 1 failed - it means you won't be able to show some region of the screen - that needs a specialized feedback to the user).

我个人认为这是安全的方式进行,因为大多数时候你想把一些服务器消息一些吐司组件拒绝回调,或提醒用户以某种方式(排队7 ajax调用并不意味着你不能显示任何东西因为1失败——这意味着你将无法显示屏幕的一些地区,需要一个专门的反馈给用户)。