Reputation: 976
I'm writing a angular service that make some http call. The code is something like this.
this.checkAndSendNotifications = function() {
UsersService.getArray(function(array) {
var notifications = [];
angular.forEach(array, function(element) {
if (some conditions is true) {
srv.sendNotificationToToken(element.id,
function() {
notifications.push({
id: user.id,
errorStatus: null,
errorStatusText: null
});
},
function(error) {
notifications.push({
id: user.id,
errorStatus: error.status,
errorStatusText: error.statusText
});
});
}
});
printNotificationsStatus(notifications);
});
};
this.sendNotificationToToken = function(id, onSuccess, onError) {
$http({
method: 'POST',
url: 'https://url....',
headers: {
'Authorization': 'Bearer ....',
'Content-Type': 'application/json'
},
data: {
"id": id,
"message": "hello"
}
}).then(function successCallback(response) {
onSuccess();
}, function errorCallback(error) {
onError(error)
});
};
I need to call the printNotificationsStatus() function only at the end of all api calls to be sure to have all api response but now the function is called at the end of angular.forEach execution and the API's promise can be resolved later because they are asyncronous.
Is there a way to wait?
Thanks in advance Davide
Upvotes: 0
Views: 3175
Reputation: 765
First I notice that you have your call to printNotificationsStatus
within the foreach so it will be called as many times as items you have in the array. If this were a synchronous process, it only needed to be out of the forEach.
But you are making an asynchronous call within the forEach.
This means that the "main" thread or execution will not wait for the response of each of the sendNotificationToToken
.
There are a couple of good patterns for this type of problems in javascript. I think the most common is as @Bruno Pares suggested: https://stackoverflow.com/a/40698868/957979
The Async library is as well a good option.
But with callbacks as you are currently using it, you can restructure the code to track the actual iteration, and after all are complete, you can call the printNotificationsStatus
this answer I think applied perfectly to what you are asking.
https://stackoverflow.com/a/18983245/957979
[Code from the link mentioned]:
function callback () { console.log('all done'); }
var itemsProcessed = 0;
[1, 2, 3].forEach((item, index, array) => {
asyncFunction(item, () => {
itemsProcessed++;
if(itemsProcessed === array.length) {
callback();
}
});
});
Upvotes: 2
Reputation: 16373
You can use $q.all to wait all promises to be resolved. Like this:
UsersService.getArray(function(array) {
var promises = [];
var notifications = [];
angular.forEach(array, function(element) {
if (some conditions is true) {
var promise = srv.sendNotificationToToken(element.id,
function() {
notifications.push({
id: user.id,
errorStatus: null,
errorStatusText: null
});
},
function(error) {
notifications.push({
id: user.id,
errorStatus: error.status,
errorStatusText: error.statusText
});
});
promises.push(promise);
}
});
// wait all promises and resolve
$q.all(promises).then(function () {
printNotificationsStatus(notifications);
})
});
};
don't forget inject $q.
Ps: in your code you are executing printNotificationsStatus() after the first iteration.
Upvotes: 2