AngularJS:在服务中链接 HTTP Promise $q

10

在AngularJS中使用$http的Promise时遇到问题。在我的服务中进行以下操作:(getSomething函数应链接两个Promise)

第二个函数使用外部回调函数!

app.service('blubb', function($http, $q) {
var self = this;
this.getSomething = function(uri, data) { return self.getData(uri).then(function(data2) { return self.compactData(uri, data2); }); };
this.getData = function(uri) { var deferred = $q.defer(); $http.get(uri).success(function(data) { deferred.resolve(data); }).error(function() { deferred.reject(); });
return deferred.promise; };
this.compactData = function(uri, data) { var deferred = $q.defer(); /* 回调函数 */ if(!err) { console.log(compacted); deferred.resolve(compacted); } else { console.log(err); deferred.reject(err); } /* 函数结束 */
return deferred.promise; }; });

当我在控制器中使用该服务时,它不会输出console.log:

blubb.getSomething(uri, input).then(function(data) {
  console.log(data)
});

编辑: 如果我自己在'compactData'中定义回调函数,则可以正常工作,但是我正在使用https://raw.github.com/digitalbazaar/jsonld.js/master/js/jsonld.js 中的“jsonld.compact”,而这个方法不起作用!

    jsonld.compact(input, context, function(err, compacted) {
      if(!err) {
        console.log(compacted);
        deferred.resolve(compacted);
      } else {
        deferred.reject('JSON-LD compaction');
      }
    });

我在jsonld.compact中获得了console.log输出,但是resolve不起作用,我不知道为什么..

只有使用$rootScope.$apply(deferred.resolve(compacted))才能正常工作。


除非compacted已经在某处定义并在作用域内,否则您可能需要将deferred.resolve(compacted);更改为deferred.resolve("compacted");,对于err也是如此。 - Beetroot-Beetroot
抱歉,compactederr是由回调函数定义的!在此函数中,console.log(compacted)也有正确的输出,但在“链接”的getSomething函数中却没有。 - Betty St
如果仍然无法正常工作,则在测试blubb.getSomething()之前分别测试blubb.getData()blubb.compactData() - Beetroot-Beetroot
我使用了$rootScope.$apply,它起作用了!(请参阅https://dev59.com/-23Xa4cB1Zd3GeqPha1B?rq=1) 但是我遇到了这个错误: “Error: $digest already in progress” - Betty St
1
请分享完整的fiddle,因为问题中没有提供很多细节。 - Ajay Beniwal
为了避免出现$digest错误,请尝试以下代码: if(!$scope.$$phase) { $scope.$apply(); } - Renaud
4个回答

5

我正在使用类似这样的链式promise:

            $http.get('urlToGo')
                .then(function(result1) {
                    console.log(result1.data);
                    return $http.get('urlToGo');
                }).then(function(result2) {
                    console.log(result2.data);
                    return $http.get('urlToGo');
                }).then(function(result3) {
                    console.log(result3.data);
                });

1
每当你使用一个在AngularJS之外运行的回调函数时,它会在新的轮/滴中运行,你必须在它被调用后在适当的作用域上调用$apply()。这让AngularJS知道它需要更新。你可能想要确保只调用一次 - 在所有承诺都已解决之后。顺便说一下,jsonld.js提供了一个promises/future API,所以如果你已经在使用promises,你不必做上面的包装器代码。相反,你可以这样做:
var promisesApi = jsonld.promises();
var promise = promisesApi.compact(input, context);

// do something with the promise

1

链式调用 Promise 在这里起作用:jsfiddle

在您的实现中,如果 $http.getcompactData 出现问题,您的 console.log(data) 将不会被调用。

您可以尝试捕获错误:

    blubb.getSomething(uri, input).then(function(data) {
       console.log(data);    
    }, function(err) {
       console.log("err: " + err);
    });

我不知道为什么,但是即使我记录了错误,也没有任何输出。 但是当我使用$rootScope.$apply时,它就正常工作了... 但是现在我得到了Error: $digest already in progress的错误。 - Betty St

0
我建议您使用工厂而不是服务。
只需从工厂返回函数并在控制器中使用即可。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接