【问题标题】:Wait for a promise to complete before processing the result在处理结果之前等待一个承诺完成
【发布时间】:2015-12-11 10:16:01
【问题描述】:

我有一个包装了第 3 方 API 的服务,我用它来将数据检索到我的控制器中。我想在显示数据之前进行一些处理以对数据进行透视,但我不知道如何在承诺完成后实现这一点。。在那之前没有数据需要处理!

我尝试了几种不同的方法,但似乎都不起作用:

angular.module('myApp').controller('myController', function ($scope, MyService) {
    $scope.getData = function () {
        MyService.getData(myParams)
            .then(function (results) {
                $scope.queryResults = results;
                // Can't do processing here, data hasn't been retrieved yet
            }, function (err) {
                $scope.alerts.push({ msg: 'Unable to get data', type: 'danger' });
            });
    }

    $scope.$watch('queryResults', function(newVals) {
        // Can't do processing here either, this only fires at
        // "$scope.queryResults = results;"
        // above where "results" is still an empty array
    });
};

还有服务:

angular.module('myApp').service('MyService', ['$q', function($q) {
    return {
        getData: function (params) {
            var operation = $q.defer();
            ThirdPartyLibrary.getData(params, { callback: function(err, results) {
                if (err == null ) {
                    operation.resolve(results);
                } else {
                    operation.reject(err, results);
                }
            }});
            return operation.promise;
        }
    }
}]);

这一定是一件很常见的事情,但我在 Google 上找不到很多东西 - 尽管我可能正在寻找错误的东西!

编辑

好的,所以我已经重构了很多东西,而潜在的问题似乎仍然是我的 Promise 链在从链中的早期返回数据之前正在进展。这是新代码:

angular.module('myApp').service('MyService', ['MyWrapperService', function(MyWrapperService) {
    var getDataForFilter = function(myApi, filter) {
        var processedResults = {};
        // This is the chain I'm having problems with
        return MyWrapperService.getRelevantKeys(myApi, filter).then(MyWrapperService.getDetailsForKeys).then(function(results){
            //do some processing here
            return processedResults;
        }, function(errors) {
            return errors;
        });
    };

    return {getDataForFilter: getDataForFilter};
}]);

angular.module('myApp').service('MyWrapperService', ['$q', function($q) {
    var getRelevantKeys = function(myApi, filter) {
        var operation = $q.defer();
        myApi.getKeys({'filter': filter, 'callback': function (err, results) {
            if (err == null) {
                    // This does get called correctly, but not until after the rest of the chain has been called.
                operation.resolve(myApi, results, filter);
            } else {
                operation.reject(err, results);
            }
        }
    };
    var getDetailsForKeys = function(myApi, keys, filter) {            
        var operation = $q.defer();
        var promises = [];
        var details = [];
        var errors = [];

        angular.forEach(keys, function (val) {
            // Get the data for each key. ***When this is called, 'keys' is still undefined.***
            promises.push(getDataForKey(myApi, val, filter).then(function(result){
                details.push(result);
            }, function(err, result) {
                errors.push(err);
            }));
        });

        $q.all(promises).then(function() {operation.resolve(details);}, function() {operation.reject(errors)});
        return operation.promise;
    };
    var getDataForKey = function(myApi, key, filter) {
        var operation = $q.defer();
        myApi.getDetail(key, {
            'filter': filter,
            'callback': function(err, results) {
                if (err == null) {
                    operation.resolve(myApi, results, activity);
                } else {
                    operation.reject(err, results);
                }
            }
        });
        return operation.promise;
    };

    return {
        getRelevantKeys: getRelevantKeys,
        getDetailsForKeys: getDetailsForKeys,
        getDataForKey: getDataForKey,
    };
}]);

不幸的是,API 让我想做的事情有点冗长,但我正在获取与过滤器相关的所有数据库键,然后获取这些键的所有值,然后旋转数据(评论在getDataForFilter) 中,然后将其传递回控制器进行显示。如果有什么不清楚的地方,我很乐意添加更多的 cmets。

(也非常感谢任何有关架构的一般性反馈!)

【问题讨论】:

  • "这只会在$scope.queryResults = results;触发" 正是你想要的,不是吗?如果results 是一个空数组,那么这意味着getData 确实导致了一个空数组。
  • 我猜是您的服务做了一些奇怪的事情,或者您实际上并没有收到您提出的请求的任何数据。
  • 它确实会返回数据,但需要几秒钟才能发生。 then(function (results) { $scope.queryResults = results; } 会立即使用一个空数组调用,然后在底层 API 调用完成后填充该数组。
  • 那么 MyService.getData 返回错误的承诺。如果您可以发布它的代码,它可能会揭示它发生的原因。
  • 显然 ThirdPartyLibrary.getData 没有做你认为它做的事情 - 关于那个图书馆的任何信息?

标签: javascript angularjs promise


【解决方案1】:

所以我完全重构了一切,现在一切正常!问题之一是忘记$q.resolve()$q.reject() 只能返回一个参数,因为我假设我可以返回尽可能多的参数(就像你可以使用匿名函数一样),然后调用then() 会全部收到。

如果有人感兴趣,我会在重构后发布我的代码,但我需要做的最低限度是替换这样的调用:

operation.resolve(arg1, arg2, arg3);

用这个:

operation.resolve({'arg1': arg1, 'arg2': arg2, 'arg3':arg3});

并相应地调整接受这些参数的函数。

【讨论】:

    猜你喜欢
    • 2016-10-16
    • 2015-12-22
    • 2019-05-29
    • 2017-06-17
    • 2019-06-30
    • 1970-01-01
    • 2020-04-22
    相关资源
    最近更新 更多