[英]JavaScript nested promise scoping and AngularJS
我在JavaScript承诺中遇到了一个真正的问题,这是我在最近几个小时内一直在尝试解决的问题,但似乎无法解决。 我对诺言的经验有限,因此我对自己的做法完全错误的想法持开放态度。
现在,我正在构建一个需要两步过程的应用程序:
这是我创建的工厂的示例:
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视图中最深层嵌套的诺言中的数据时。 具体来说,我想在ng-repeat
语句中使用该诺言中的数据。 但是,无论我尝试什么,它都不会显示。 我试图在promise中分配数据而不是返回,就像这样:
service.getData('dataStore').then(function(result) {
// Retrieve data
// Assigned the enclosing scope's this to 'self'
self.data = result;
}, errorFunction);
那也不行。 我尝试了多种其他方法,但似乎无法将这些数据显示在视图中。 让它显示在console.log(data)
调用中没有问题,所以我知道数据可以正确返回。 有没有人有解决这样的问题的经验?
我建议您尽量避免嵌套承诺。 您可以看一下这篇博客文章 ,该文章将使您了解如何避免“无极汤”,而可以实现承诺链。
关于您的问题,我建议以下内容:
一个快速的解决方案是解决您的问题。 您返回错误的工厂方法:
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
})
所有这些都应该经过测试-如果您想要一个可行的解决方案,则可以添加一个插件或jsbin ...
编辑
我认为您在这里还有另一个问题。 您正在serviceFactory
和service
之间混合service
。 我不确定我是否了解这是同一服务还是谁。 您能否提供更详细的代码或添加plunker / jsbin等。
我已经编辑了这个答案,我最初删除了这个答案,因为我没有很清楚地解释我的意思,并且赢得了一些反对意见(没有解释,但这是我的猜测)。 无论如何,这是一个更完整的答案。
我怀疑您的问题是您使用的任何PaaS都不了解Angular,而Angular同样也不了解PaaS。 您在问题中说,PaaS具有返回承诺的方法,但是如果Angular不知道这些承诺,那么当承诺解决时,Angular不知道更新DOM。 Angular通过摘要循环执行此操作,在该摘要循环中,Angular会检查其正在监视的所有内容以查看其是否已更改。 当使用$q
(或像其他角服务$http
),角知道自动揭开序幕消化周期时,他们解决。 但是,通过其他方式创建的承诺无法解决时,它不会启动摘要循环。
我认为这就是您的代码中正在发生的事情。 您的PaaS给您的诺言已经很好地解决了(您说可以通过控制台查看结果),但是您的HTML尚未更新。
我修改了我们正在研究的plunkr ,以演示其实际效果。 我创建了一个模拟PaaS(不知道您在使用什么),它使用jQuery
创建了promise并解决了它们。 如您所见,当promise解析时,结果将记录到控制台,但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>"
};
});
我最初建议您可以在捕获诺言的结果后添加$scope.$apply()
来解决此问题。 我分叉了Plunker,您可以在这里看到它的确,实际上是在更新DOM。
.controller("DataController", function ($scope, dataFactory) {
var vm = this;
dataFactory.getData().then(function(result){
console.log(result);
vm.dataArr = result;
$scope.$apply();
});
})
但是,还有一个惯用的解决方案。 当您从Angular中获得需要在Angular中使用的promise时 , 可以使用$ q.when (Angular知道的Promise)包装该Promise ,并且当外部Promise解析时,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) 在这里对此问题做了很好的解释。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.