我的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
语句中使用该承诺中的数据。但无论我尝试什么,它都不会出现。我试图在承诺中分配数据而不是返回,如下所示:
service.getData('dataStore').then(function(result) {
// Retrieve data
// Assigned the enclosing scope's this to 'self'
self.data = result;
}, errorFunction);
这也不起作用。我尝试过各种其他方法,但我似乎无法将这些数据提供给视图。在console.log(data)
调用中显示它没有问题,因此我知道数据正确回传。有没有人有解决这样问题的经验?
答案 0 :(得分:0)
我建议你尽量避免嵌套的承诺。你可以看一下this blog post,它会让你看到如何避免'承诺汤'并承诺链接。
关于你的问题,我建议如下:
快速解决方案将是解决您的问题。您返回的工厂方法错误:
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等吗?
答案 1 :(得分:-2)
我已经编辑了这个答案,我最初删除了这个答案,因为我没有清楚地解释我的意思,并且它获得了一些downvotes(没有解释,但这是我的猜测)。无论如何,这是一个更完整的答案。
我怀疑你的问题是,无论你使用什么PaaS都没有意识到Angular,Angular同样也没有意识到PaaS。你在问题中说PaaS有返回promises的方法,但是如果Angular不知道这些promise,那么,当promises解决时,Angular不知道更新DOM。 Angular通过摘要循环执行此操作,这是Angular检查所有正在观察的内容以查看其是否已更改的位置。使用$q
(或其他Angular服务,如$http
)时,Angular知道在解析时会自动启动摘要周期。但是,当通过其他方式创建的承诺解决时,它不会启动摘要周期。
我认为这是您的代码中发生的事情。您的PaaS正在为您提供正确解决的承诺(您说您可以通过控制台查看结果),但您的HTML未更新。
I modified the plunkr我们正在努力证明这一点。我创建了一个模拟PaaS(不知道你在使用什么),使用jQuery
创建promises并解析它们。如您所见,当promises解析时,结果将记录到控制台,但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,你可以看到它here,实际上更新了DOM。
.controller("DataController", function ($scope, dataFactory) {
var vm = this;
dataFactory.getData().then(function(result){
console.log(result);
vm.dataArr = result;
$scope.$apply();
});
})
然而,有一个更惯用的解决方案。当你从Angular中获得一个你需要在Angular中使用的承诺时,you can wrap that promise using $q.when(一个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对此问题here给出了很好的解释。