[英]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.