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