我有一个递归查询,需要根据结果进行进一步的查询。理想情况下,我希望能够构建一个promise链,以便我知道所有查询何时最终完成。
我一直在使用example from this question,我有以下方法:
this.pLoadEdges = function(id,deferred) {
if (!deferred) {
deferred = $q.defer();
}
$http.post('/Create/GetOutboundEdges', { id: id }).then(function(response) {
var data = response.data;
if (data.length > 0) {
for (var i = 0; i < data.length; i++) {
var subID = data[i].EndNode;
edgeArray.push(data[i]);
self.pLoadEdges(subID, deferred);
}
} else {
deferred.resolve();
return deferred.promise;
}
});
deferred.notify();
return deferred.promise;
}
然后我从其他地方开始使用:
self.pLoadEdges(nodeID).then(function() {
var edgedata = edgeArray;
});
当然我打算用edgeArray做更多的事情。
问题是只要任何单个路径到达终点,就会触发then()函数,而不是在 all 路径完成时触发。一条特定的路径可能很浅,另一条路可能很深,我需要知道所有的路径何时被探索过并且它们都完成了。
如何基于这个递归查询构造一个promise数组,理想情况是我可以使用$ q.all []知道它们何时完成,当promise数组中的promise数量依赖于查询的结果?
答案 0 :(得分:2)
我不是100%肯定该函数的最终结果应该是什么,但它看起来应该是基于您提供的示例的平面数组边。如果这是正确的,那么以下内容应该有效
public void addToNewPlaylist(){
Tab nTab = new Tab();
FXMLLoader nLoader = new FXMLLoader(getClass().getResource("/fxml/fxPlaylist.fxml"));
try {
Parent nRoot = nLoader.load();
PlaylistController controller = nLoader.getController();
controller.setTracks(table.getSelectionModel().getSelectedItems());
nTab.setContent(nRoot);
} catch (IOException e) {
e.printStackTrace();
}
tabPane.getTabs().add(nTab);
}
用法:
this.pLoadEdges = function(id) {
var edges = [];
// Return the result of an IIFE so that we can re-use the function
// in the function body for recursion
return (function load(id) {
return $http.post('/Create/GetOutboundEdges', { id: id }).then(function(response) {
var data = response.data;
if (data.length > 0) {
// Use `$q.all` here in order to wait for all of the child
// nodes to have been traversed. The mapping function will return
// a promise for each child node.
return $q.all(data.map(function(node) {
edges.push(node);
// Recurse
return load(node.EndNode);
});
}
});
}(id)).then(function() {
// Change the return value of the promise to be the aggregated collection
// of edges that were generated
return edges;
});
};
答案 1 :(得分:1)
您需要$q.all
功能:
将多个promises组合成一个promise,当所有输入promise都被解析时解析。
查看此演示:JSFiddle
控制器可以像下面的代码一样(好吧,你可能想把它放在factory
中)。
首先加载用户列表,然后为每个用户加载该用户的帖子。我使用JSONPlaceholder
来获取虚假数据。
$q.all
接受一系列承诺并将它们合并为一个承诺。消息All data is loaded
仅在加载所有数据后显示。请检查控制台。
angular.module('Joy', [])
.controller('JoyCtrl', ['$scope', '$q', '$http', function ($scope, $q, $http) {
function load() {
return $http.get('http://jsonplaceholder.typicode.com/users')
.then(function (data) {
console.log(data.data);
var users = data.data;
var userPromises = users.map(function (user) {
return loadComment(user.id);
});
return $q.all(userPromises);
});
}
function loadComment(userId) {
var deferred = $q.defer();
$http.get('http://jsonplaceholder.typicode.com/posts?userId=' + userId).then(function (data) {
console.log(data);
deferred.resolve(data);
});
return deferred.promise;
}
load().then(function () {
console.log('All data is loaded');
});
}]);
您需要一个递归函数,因此,请检查:JSFiddle。
代码如下。由于假API,我使用round
跳出递归。关键在于:$q.all(userPromises).then(function () { deferred.resolve(); });
。这告诉我:Please resolve this defer object after all promises are resolved
。
angular.module('Joy', [])
.controller('JoyCtrl', ['$scope', '$q', '$http', function ($scope, $q, $http) {
var round = 0;
function load(userId) {
return $http.get('http://jsonplaceholder.typicode.com/posts?userId=' + userId)
.then(function (data) {
var deferred = $q.defer();
console.log(data.data);
var posts = data.data;
if (round++ > 0 || !posts || posts.length === 0) {
deferred.resolve();
} else {
var userPromises = posts.map(function (post) {
return load(post.userId);
});
$q.all(userPromises).then(function () {
deferred.resolve();
});
}
return deferred.promise;
});
}
load(1).then(function () {
console.log('All data is loaded');
});
}]);
答案 2 :(得分:0)
您可以尝试构建返回的promises数组,然后使用$.when.apply($, <array>)
模式。我之前用它来完成与你所描述的类似的事情。
更新:
您可能还想阅读apply function上的文档,它非常整洁。