【问题标题】:Return value from nested http.put从嵌套的 http.put 返回值
【发布时间】:2016-04-10 11:34:17
【问题描述】:

如何将 http.put 的响应对象作为 TestFunction 的返回值返回给控制器? http.get 的响应打印正常,但 putResponse 未定义。在调试期间,我可以看到 http.put 在服务器上更新数据。

  testFunction: function (url, data) {
        var etag;
        var putResponse;
        $http.get(url).then(function successCallback(response) {
            if (response.data != null) {
                etag = response.headers(['etag']);
                 $http.put(url, data, { headers: { 'If-Match': etag } }).then(function successCallback(response) {
                     putResponse = response;
                }, function errorCallback(response) {
                    // handle error
                });
            }
            else {
                // handle error

            }

        }, function errorCallback(response) {
            // handle error

        });
        console.log(putResponse);

    }

【问题讨论】:

    标签: angularjs angularjs-service angularjs-http


    【解决方案1】:

    $http.get$http.put 与其余代码异步执行。 您在异步调用中拥有 console.log。所以它在返回之前被调用。

    此外,如果您希望将 putResponse 返回给“调用者”,您必须同时返回 putResponse 和承诺:

      testFunction: function (url, data) {
            var etag;
            var putResponse;
            var promise = $http.get(url).then(function successCallback(response) {
                if (response.data != null) {
                    etag = response.headers(['etag']);
                    return $http.put(url, data, { headers: { 'If-Match': etag } })
                }
                else {
                    // handle error
                    // $q.reject();    
                }
    
            }).then(function successCallback(response) {
                putResponse = response;
                console.log(putResponse); // this gets called after the server responds ( defined ) 
                return putResponse;
            })
            ["catch"](function (response) {
                     // handle error
            });
    
            console.log(putResponse); // this gets called before the server responds ( undefined )
            return promise;
        }
    

    现在你可以使用

    tesFunction(arg1, arg2).then(function(response){ /* in here you have response defined */ })
    

    【讨论】:

    • 谢谢,testFunction 现在可以了,putResponse 的控制台输出也可以了。我无法使用 testFunction(url,data).then(function(response){ /* 在这里您已定义响应 */ }) 将 putResponse 返回给调用者 ...仅显示来自 get 的响应?
    • 是的,你是对的,我已经更新了我的答案。这样,get 中的 if else 也必须返回一个 Promise,否则您将遇到错误。
    • 是的,这样就可以了!响应成功返回给调用者。总结一下:首先你必须返回 putResponse 然后是 promise 和 catch 你必须处理来自 put 的错误。
    【解决方案2】:

    一种方法是使用$q.all() 返回多个承诺。

    工作 JSFiddle:https://jsfiddle.net/sscovil/waxL8Lt8/

    在该示例中,我使用 $httpProvider 拦截器来模拟 HTTP 响应;这与您的需要无关,仅用于说明。

    重要的是myRestService函数:

    function myRestServiceFactory($http, $q) {
      return function() {
        var deferredGet = $q.defer();
        var deferredPut = $q.defer();
        var promises = {};
    
        promises.get = deferredGet.promise;
        promises.put = deferredPut.promise;
        $http.get('https://example.com').then(onGetSuccess, onGetError);
    
        return $q.all(promises);
    
        function onGetSuccess(response) {
          if (response.data != null) {
            var etag = response.headers(['etag']);
            var config = {
              headers: {'If-Match': etag}
            };
            $http.put('https://example.com', {}, config)
              .then(onPutSuccess, onPutError);
            deferredGet.resolve(response);
          } else {
            deferredGet.reject(response);
          }
        }
    
        function onGetError(error) {
          deferredGet.reject(error);
        }
    
        function onPutSuccess(response) {
          deferredPut.resolve(response);
        }
    
        function onPutError(error) {
          deferredPut.reject(error);
        }
      }
    }
    

    注意它使用$q.defer() 创建两个promise,然后返回$q.all(promises)。这将返回一个单一的承诺,您可以通过.then() 将回调附加到该承诺,并且回调将接收到承诺响应的映射,如下所示:

    function MyController($scope, myRestService) {
        $scope.values = {};
        myRestService().then(function (values) {
          $scope.values.get = JSON.stringify(values.get);
          $scope.values.put = JSON.stringify(values.put);
      });
    }
    

    【讨论】:

    • 这是另一种方法。到目前为止,我一直在避免使用 $q.defer 但是在你的解释之后看起来很容易!根据您的意见,哪种方法是最好的(更容易)您的方法还是上面的方法(不使用 $q)?
    • 哪个更容易?那是主观的。但我认为我的方法在阅读代码时更容易遵循。
    • 不错的方法!不同之处在于,在此您只返回我的两个承诺。可读性仅依赖于命名匿名函数 imo,这两种方法都可以做到。
    • 啊,我误会了。认为 OP 想要两个解决方案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-02-04
    • 1970-01-01
    • 2016-03-02
    • 2013-10-26
    • 2015-01-15
    • 1970-01-01
    • 2014-02-21
    相关资源
    最近更新 更多