javascript Promise API - 结合 2 个异步调用的结果

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16307652/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 04:08:45  来源:igfitidea点击:

Promise API - combining results of 2 asynchronous call

javascriptangularjspromise

提问by bsr

With promise API, how to send two asynchronous request in parallel, and resolve the combined result as the response.

使用promise API,如何并行发送两个异步请求,并将合并的结果解析为响应。

var get = function(id){
            var res1, res2;
            var deferred = $q.defer();
            Db.get(id, "abc")
                .then(function (d) {
                    //deferred.resolve(d));
                    res1 = d;
                }, function (e) {
                    //error
                });

            Db.get(id, "def")
                .then(function (d) {
                    //deferred.resolve(d));
                    res2 = d;
                }, function (e) {
                    //error
                });

            //?????? how to return {res1:res1 , res2: res2}

            return deferred.promise;
        };

now, when I call get() like

现在,当我调用 get() 时

get(123).then(function(d)){
// d= {res1: res1, res2: res2}
},
...

I need to get the combined result as indicated. How to do this with Angular promise API?

我需要得到所示的组合结果。如何使用 Angular promise API 做到这一点?

回答by ForbesLindesay

As @Matt said, you need to use $q.all, but the usage isn't quite right. AngularJS doesn't support .doneand .failand they don't work quite like that anyway in that there's no such thing as a promise for multiple values, instead you just have a promise for an array.

正如@Matt 所说,您需要使用$q.all,但用法不太正确。AngularJS 不支持.done并且.fail它们也不会像那样工作,因为没有对多个值的承诺这样的东西,相反,您只有对数组的承诺。

If you were writing this using the full Qwe would write:

如果你用完整的Q写这个,我们会写:

var get = function (id) {
    return Q.all([Db.get(id, "abc"), Db.get(id, "def")])
        .spread(function (res1, res2) {
            return {res1: res1, res2: res2};
        });//the error case is handled automatically
};

In this case, .spreadacts like .thenexcept that it spreads the results of an array for a promise out over the arguments of its onFulfilledfunction. To change this to use the promise methods from AngularJS we just need to make do without .spread. This leads to the following solution:

在这种情况下,除了它将一个 promise 数组的结果扩展到其函数的参数之外,它的.spread作用类似于。要将其更改为使用 AngularJS 的 promise 方法,我们只需要在没有. 这导致以下解决方案:.thenonFulfilled.spread

var get = function (id) {
    return $q.all([Db.get(id, "abc"), Db.get(id, "def")])
        .then(function (res) {
            return {res1: res[0], res2: res[1]};
        });//the error case is handled automatically
};

The beauty of this is that we are freed from handling all the nitty grity of error propagation and storing the partial results because .thenacts as a filter. If you leave out the error handler, it automatically propagates any errors. This means that if either of the input promises are rejected, the result will be rejected. If both promises are fulfilled successfully, res is the array of those resolution values.

这样做的好处在于,我们无需处理错误传播的所有细节,也无需存储部分结果,因为.then它充当了过滤器。如果您省略错误处理程序,它会自动传播任何错误。这意味着如果任何一个输入承诺被拒绝,结果将被拒绝。如果两个承诺都成功实现, res 是这些分辨率值的数组。

回答by PhiLho

I have something to add to @ForbesLindesay answer.

我有一些东西要添加到@ForbesLindesay 的答案中。

In our case, we wanted partial results: if a request failed (eg. server has an hiccup, we request something deleted by somebody else, etc.), we still want to collect the valid responses, and to report the errors.

在我们的例子中,我们想要部分结果:如果请求失败(例如,服务器出现故障,我们请求其他人删除了某些内容等),我们仍然希望收集有效响应,并报告错误。

I found out that we need to handle success and failure on each promise, returning a value that will be collected by $q.all.

我发现我们需要处理每个 promise 的成功和失败,返回一个将由$q.all.

Here is our code, simplified and made generic ('item'...):

这是我们的代码,简化并通用('item'...):

var promiseList = _.map(itemList, function(item)
{
    return DataService.getISubtems(item.id)
        .then(
            function(response)
            {
                var subItems = response.data;
                $log.info('Received sub-item list;' + subItems.length + ';items received');
                return subItems;
            },
            function(reason)
            {
                $log.warn('Sub-item list not received for item;' + item.name + ';' + item.id);
                $scope.errorList.push('Sub-item list not received for item "' + item.name + '"');
            }
        );
});
$q.all(promiseList)
    .then(function(itemArray)
    {
        // We get an array of arrays interleaved with undefined value when an error was raised.
        // That's because error handling doesn't return anything, ie. returns undefined.
        // We remove these undefined values then put all operations at the same level.
        var allOperations = _(operationArray).reject(_.isUndefined).flatten().value();
        if ($scope.errorList.length > 0)
        {
            NotificationService.warning('Items Fetching', 'Errors while getting item list:\n' +
                $scope.errorList.join('\n'));
        }
        $scope._onItemListReceived(allItems);
    });

Note that we use Lodash (_.map, _.flatten, _.reject, _.isUndefined) but I think the usage is quite clear (that's the nice point of this library!).

请注意,我们使用 Lodash (_.map, _.flatten, _.reject, _.isUndefined) 但我认为用法很清楚(这是这个库的优点!)。

回答by Dag H?idahl

You can use the angular-q-spreadlibrary and then use the same code as @ForbesLindesay's first example:

您可以使用angular-q-spread库,然后使用与@ForbesLindesay 的第一个示例相同的代码:

// The module needs $q-spread as a dependency:
// angular.module('…', ['$q-spread']);

var get = function (id) {
    return $q.all([Db.get(id, "abc"), Db.get(id, "def")])
        .spread(function (res1, res2) {
            return {res1: res1, res2: res2};
        });
};