Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/angularjs/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
JavaScript嵌套承诺范围和AngularJS_Javascript_Angularjs_Promise_Angular Promise - Fatal编程技术网

JavaScript嵌套承诺范围和AngularJS

JavaScript嵌套承诺范围和AngularJS,javascript,angularjs,promise,angular-promise,Javascript,Angularjs,Promise,Angular Promise,在过去的几个小时里,我一直在努力解决JavaScript承诺的问题,但似乎无法解决。我在承诺方面的经验有限,因此我认为我的方法根本不正确 现在,我正在构建一个需要两步流程的应用程序: 连接到外部PaaS服务,该服务返回承诺 在这个承诺范围内,检索一些数据 以下是我创建的一个工厂的示例: app.factory('serviceFactory', [ function() { var getData = function getData() { se

在过去的几个小时里,我一直在努力解决JavaScript承诺的问题,但似乎无法解决。我在承诺方面的经验有限,因此我认为我的方法根本不正确

现在,我正在构建一个需要两步流程的应用程序:

连接到外部PaaS服务,该服务返回承诺 在这个承诺范围内,检索一些数据 以下是我创建的一个工厂的示例:

app.factory('serviceFactory', [
    function() {
        var getData = function getData() {
            service.connect(apiKey).then(function() {
                    service.getData('dataStore').then(function(result) {
                        // Retrieve data
                        return result;
                    }, errorFunction);
                },
                errorFunction);
        };
        return {
                getData: getData
        };
    }

]);
正如你所看到的,这里有嵌套的承诺。导致我出现问题的是,我试图使用AngularJS视图中嵌套最深的promise中的数据。具体来说,我想在ng repeat语句中使用来自该承诺的数据。但不管我怎么尝试,它都不会出现。我尝试在承诺范围内分配数据,而不是返回,如下所示:

service.getData('dataStore').then(function(result) {
    // Retrieve data
    // Assigned the enclosing scope's this to 'self'
    self.data = result;
}, errorFunction);

那也不行。我尝试过多种其他方法,但我似乎无法将这些数据放到视图中。让它显示在console.logdatacall中没有问题,因此我知道数据返回正确。有人解决过这样的问题吗?

我编辑了这个答案,我最初删除了这个答案,因为我没有很清楚地解释我的意思,它在没有解释的情况下赢得了一些反对票,但这是我的猜测。无论如何,这里有一个更完整的答案

我怀疑您的问题是,您使用的任何PaaS都不知道Angular,Angular也不知道PaaS。您在问题中说PaaS有返回承诺的方法,但是如果Angular不知道这些承诺,那么当承诺解决时,Angular不知道更新DOM。Angular通过摘要循环完成这项工作,在摘要循环中,Angular检查它正在监视的所有内容,以查看是否发生了变化。当使用$q或其他Angular服务(如$http)时,Angular知道在解析时自动启动摘要周期。然而,当通过其他方式做出的承诺得以解决时,它并没有启动一个消化周期

这就是我认为在你的代码中发生的事情。您的PaaS向您做出了承诺,这些承诺得到了正确的解决。您说过可以通过控制台查看结果,但您的HTML并没有得到更新

我们正在努力在行动中证明这一点。我创建了一个不知道您在使用什么的模拟PaaS,它使用jQuery创建承诺并解析承诺。正如您所看到的,当解析承诺时,结果被记录到控制台,但DOM没有解析

angular.module("app",[])
  .value("mockPaaS", mockPaaS)
  .factory("dataFactory", function($q, mockPaaS){

    function getData(){
      return mockPaaS.connect()
        .then(mockPaaS.getData);
    }
    return {
      getData: getData
    }
  })
  .controller("DataController", function (dataFactory) {
      var vm = this;
      dataFactory.getData().then(function(result){
        console.log(result);
        vm.dataArr = result;
      });
  })
  .directive("myApp", function(){
      return {
        bindToController: true,
        controller: "DataController",
        controllerAs: 'myApp',
        template: "<div ng-repeat='i in myApp.dataArr'>{{i}}</div>"
    };
  });
然而,有一个更为惯用的解决方案。当你从外部angular得到一个承诺,你需要在angular中使用,一个有角度意识的承诺,当外部承诺解决时,angular应该自然地开始它的消化循环

  .factory("dataFactory", function($q, mockPaaS){
    function getData(){
      return $q.when(mockPaaS.connect()
        .then(mockPaaS.getData));
    }
    return {
      getData: getData
    }
  })
  .controller("DataController", function (dataFactory) {
      var vm = this;
      dataFactory.getData().then(function(result){
        console.log(result);
        vm.dataArr = result;
      });
  })

Ben Nadel对这个问题给出了很好的解释。

我建议你尽量避免重复承诺。你可以看看,这将让你看到如何避免“承诺汤”,而改用承诺链

关于你的问题,我建议如下:

一个快速的解决办法就是解决你的问题。您返回的工厂方法错误:

app.factory('serviceFactory', [
    function() {
        var getData = function getData() {
            return service.connect(apiKey).then(function() {
                    service.getData('dataStore').then(function(result) {
                        // Retrieve data
                        return result;
                    }, errorFunction);
                },
                errorFunction);
        };//here you should close the 'getData method
        return {
            getData: getData
        };   
    }
]);
但是,您可以重构代码以链接您的承诺。比如:

app.factory('serviceFactory', [
    function() {
        var connect = function connect() {
            return service.connect(apiKey);
        };
        var getData = function getData(data) {
            return service.getData(data);
        };       
        return {
            getData: getData,
            connect: connect
        };
    }
]);
现在,您可以这样做:

serviceFactory.connect(apiKey)
     .then(serviceFactory.getData)
     .then(function(result){
           //use data here
      })
所有这些都应该经过测试——如果您想要一个有效的解决方案,您可以添加一个plunker或jsbin

编辑


我想你还有一个问题。您正在混合serviceFactory和service。我不确定我是否理解这是同一项服务,或者谁是谁。您可以提供更详细的代码或添加plunker/jsbin等吗?

您没有显示服务是如何获取数据的,但听起来您需要调用$scope。$apply无论在何处使用它,您介意详细说明一下吗?通常,如果您在某个时候使用$http调用服务,angular为您处理消化循环。但是,如果您使用其他方法(非角度方法)来获取数据,则必须使用$apply手动启动摘要,以便angular知道数据已到达。您需要返回service.connect生成的承诺。然后作为getData btw的结果,这是什么服务?你能在你的控制器中显示使用serviceFactory.getData的代码吗?我会尝试链接,但现在我发现我刚才输入的代码不正确。return语句实际上在getData之外,所以这不是问题所在。我将对其进行编辑以反映这一点。请查看我的链接解决方案。如果您想要一个快速的解决方案,而不需要链接,您只需在“service.connect”中添加一个“return”。但承诺都是为了避免这种回调地狱…请注意return service.connectapiKey.thennfunction{,在我的第一个解决方案中,我意识到我的措辞本可以更好,特别是因为Angular中存在“服务”的概念。为了澄清,“serviceFactory”
是承诺的工厂,“服务”是我连接到的PaaS服务。请看我的最终编辑。这对你有意义吗?
serviceFactory.connect(apiKey)
     .then(serviceFactory.getData)
     .then(function(result){
           //use data here
      })