【问题标题】:Unwrapping a promise to be returned from a HTTP service解包从 HTTP 服务返回的承诺
【发布时间】:2015-11-18 10:58:42
【问题描述】:

所以我正在做一个项目,我有一个数据集,我必须根据用户输入通过从服务器检索数据来检索所述数据集的各种统计数据。

我正在尝试设置一个 AngularJS 服务,该服务具有各种方法,可以返回给定数据点的各种信息。

这是来自服务的公共方法:

function test() {
    return $http.get('blahblah.api.../datapoint1')
    .success(function(data) {
        console.log(data.name);
        return data.name;
    });
}

这是控制器的相关部分:

self.data = service.test();
console.log(self.data);

有趣的是,http 调用成功中的 console.log(data.name) 正是我想要的。给定数据点的名称。 但是,其范围之外的 console.log(self.data) 给了我原始的承诺对象。我用来发送“成功”范围之外的信息的任何方法都会给我一个承诺对象。为什么是这样?有没有办法解决这个问题?必须处理控制器中的错误处理似乎非常低效。

【问题讨论】:

    标签: angularjs api http


    【解决方案1】:

    没有办法使该服务同步,您应该始终使用承诺。

    试试这个:

    function test() {
        return $http.get('blahblah.api.../datapoint1')
        .success(function(data) {
            console.log(data.name);
            return $q.resolve(data.name);
        });
    }
    

    然后是这个:

    service.test().then(function (name) {
        self.data = name;
        console.log(self.data);
    })
    

    编辑:

    关于您获得承诺的原因认为您的代码与以下内容相同:

    function something(data) {
       console.log(data.name);
       return data.name;
    }
    
    function test() {
        return $http.get('blahblah.api.../datapoint1')
        .success(something);
    }
    

    您的代码将调用的结果返回成功,这确实是一个承诺。

    【讨论】:

    • 我明白了。谢谢!为什么它不能同步的任何具体原因?或解释原因的链接?我假设有充分的理由必须这样做。
    • 当然:stackoverflow.com/questions/13088153/…。另请注意,javascript 根据定义是异步的,所以即使它是可能的(如果你使用 Jquery 或普通的旧 XHR,但这是一种已弃用的行为)它根本不推荐
    【解决方案2】:

    你没有为你的函数创建一个新的承诺。

    查看您的test 函数。看看你如何有两个回报?第一次,您返回$http.get 函数,这是一个promise,但是一个解析为success 函数的promise。您从成功函数返回的内容并没有解决该承诺——它已经在成功函数中解决了。

    相反,您需要为您的服务函数创建一个新的承诺并将其返回给您的应用。

    您应该如何构建请求

    function test() {
        // Setup a promies for this function to return
        var deferred = $q.defer()
    
        $http.get('blahblah.api.../datapoint1')
        .success(function(data) {
            console.log(data.name);
    
            // Return our data to use in our app
            deferred.resolve(data);
        });
    
        // Return the promise
        return deferred.promise
    }
    

    实施

    service.test().then(function(data){
          self.data = data
          console.log(self.data.name) //should be the same as in your service
    });
    

    请注意,您需要在服务中包含 $q 注入器。

    【讨论】:

    • 绝对没有理由创建第二个承诺。 $http 已经返回一个。
    • 只是好奇你为什么要做出新的承诺?那不是意味着要处理更多的东西吗?为什么不直接从 http.get() 返回原始承诺。还是我们这样做是为了同时处理服务和控制器中的错误处理?
    • 不需要处理更多的东西,只是没有必要。
    • 您当然不必这样做,但这是文档所倡导的模式:docs.angularjs.org/api/ng/service/$q。我对上面 Kevin 实现的唯一问题是你最终得到了至少两个 then/catch 函数。如果您所做的只是返回由$http 检索到的值,那么您也可以直接在使用该服务的任何代码中处理它。
    【解决方案3】:

    不,在 promise 解决之前,不可能以任何有意义的方式将该值传递给外部范围。您必须从回调中访问它。至于错误处理,当然仍然可以由您的服务处理。

    function test() {
        return $http.get('blahblah.api.../datapoint1')
        .then(function(response) {
            console.log(response.data.name);
            return response.data.name;
        }).catch(function (e) {
            // error handling...
        });
    }
    
    self.data = ''; // default value
    service.test().then(function (name) {
        self.data = name;
        console.log(self.data); // correct value
    });
    console.log(self.data); // still default value
    

    我建议不要使用.success() 和.error(),而改用.then() 和.catch(),前两者在最新版本的AngularJS 中已被弃用。

    【讨论】:

      猜你喜欢
      • 2017-02-21
      • 1970-01-01
      • 2018-03-15
      • 1970-01-01
      • 1970-01-01
      • 2017-02-22
      • 2017-06-08
      • 2014-05-01
      • 2017-08-04
      相关资源
      最近更新 更多