What is purpose of this angularJS code? - javascript

Could someone explain to me what this code does? I know that it fetches countries and push them to the list which is shown in a web page, but why? I think that $scope.countries = service.query() is enough or is this way to avoid Asynchronous Problems?
$q.all([$scope.address.$promise, $scope.countrys.$promise]).then(function() {
if (!$scope.address.country.id) {
return $q.reject();
}
return Country.get({id : $scope.address.country.id}).$promise;
}).then(function(country) {
$scope.countrys.push(country);
});

Descriptions in code comments. This is conditionally data loading process using promise mechanism. Try to specify your question more detailed if is is not enough for you
// if address and countries was loaded (probably from ajax request)
$q.all([$scope.address.$promise, $scope.countrys.$promise]).then(function() {
// if address doesn't exist reject all actions
if (!$scope.address.country.id) {
return $q.reject();
}
// otherwise load country based on address field as a promise
return Country.get({id : $scope.address.country.id}).$promise;
}).then(function(country) {
// when loading process is finished add country to dataset
$scope.countrys.push(country);
});
According to $q service documentation
$q.all([promise1, promise2, ...])
Combines multiple promises into a single promise that is resolved when
all of the input promises are resolved.

service.query() will inevitably return a promise, which resolves when the asynchronous call completes. It would make no sense to set the scope property (which you will no doubt bind to some form of list) with a promise.
What the code is doing is waiting for the promise(s) to resolve, performing some logic, and setting the resulting data to a scope property.

Related

Should I have been returning a promise all along?

I have been calling a method MediaNext() from several points in my PlayersController code to chain the next Media playback if any.
This MediaNext() method returns a Media object from some of the various playlists I have from memory. So it tries to encapsulate the notion of getting the next Media object if any left.
However, recently I revised MediaNext() that for some new condition X I now have to load external data in order to return this alternative Media object.
MediaNext():any { // any could be typed like Media_I
if(cond1) {
...
return Media1
}
if(cond2) {
...
return Media1
}
//
if(! AutoPlayNext) return null;
//
if(NoMoreMedia) return null;
//
If (condX) {
// in order to wait for the Load() method I am subscribing to its promise
this.Service1.Load(Media).then(() => {
...processing...
return Media
})
??? what do I return here, it does not make sense to return null, since potentially a Media is on its way ???
}
return null // safe catch. nomore media should not happen.
}
The questions I have
By subscribing to the promise of the .Load(), the execution from what I gather in JS should not be blocked waiting for the media data to return. Instead the execution needs to flow and the call to MediaNext() has to return. However, what could I be returning where indicated in the code above "???".
Should MediaNext() have been coded to return a promise for all conditions?
I mostly do guess work when I code promises and observables as they remain a beast to understand and master so feel free to advise alternatives.
Thank you for your help.
If you deal with .Load asynchronously and immediately return, there's no good reason for that function to return anything. The operation is still happening in the backend.
However, if you want the caller to get more information about if the operation was successful or not, you should return a promise.
If you want to return a promise, you might find it much easier to write this as an async function, and use await this.Service1.Load(). instead of then().
You method is now asynchronous and you are using a Promise. You then need to return a promise which your consumers can wait on to get a result. Either:
1) Return the promise
If (condX) {
return this.Service1.Load(Media);
}
2) Set your method as async and await the promise used internally
async MediaNext():any { // any could be typed like Media_I
// ...
If (condX) {
return await this.Service1.Load(Media);
}
// ...

promise call separate from promise-resolution

I'm not so familiar with promises.
I would like hide promise-implementation from promise-call.
Example:
function findFriends(req, res) {
const promiseFriend = MyFriendes.find({}).exec(); //call promise
if(friends.length===0){
logger.warn('No friendsavailible');
}else if(friends === undefined){
res.status(500).json({
error: 'INTERNAL ERROR'
});
}else{
res.status(200).json({
friends: friends
});
}
}
and I will resolve my promise within same file but not
at same function, where I call this promise.
promiseFriend
.then(function(friends){
return friends;
})
.catch(function(err){
logger.error({error:err});
});
Now, I get, that "promiseFriend" is undefined.
How can I separate promise-call from promise-resolution?
If you want to define a promise in a function and use it somewhere else then first of all you need to return the promise from that function, which you're not doing in your code. Then you need to actually call that function which you are also not doing. And finally you need to use a then callback on the returned value, which you are not doing in this case as well.
There is no point in saving the promise in a local variable promiseFriend that is scoped to this function. There is also no point to return a value in your then callback: .then(function (friends) { return friends; }) - I have no idea what have tried to do here.
I suppose that findFriends is supposed to be a route handler for Express. If so then make sure that you send a response in every case (which you don't do for friends.length===0). Also, you need to actually add a then handler to the saved promise if you want to act when it's resolved. Right now you don't even have friends defined in your function. Also add a catch handlers and also send a response for that case.
Then you might return the promise from your function but not if it is a route handler, it doesn't make sense. You can return a promise from a function:
function x() {
return MyFriendes.find({}).exec();
}
and then use it:
x().then(friends => ...).catch(error => ...);
but you cannot use return values if you don't return it, you can't use undefined variables as if they were defined, and you actually need to consider who is your return value returned to.
I suggest that you learn how Node actually works because it seems that you have copied and pasted some random code, joined it together and expect that it does what you want without actually trying to understand it.
To get a better understanding on the asynchronous nature of Node that is giving this execution order here, see those answers:
A detailed explanation on how to use callbacks and promises
Explanation on how to use promises in complex request handlers
An explanation of what a promise really is, on the example of AJAX requests
An explanation of callbacks, promises and how to access data returned asynchronously
Don't try to write Node programs before you understand the concept of function calls, return values, callbacks and in this case promises.

When to use promise.all()?

This is more of a conceptual question. I understand the Promise design pattern, but couldn't find a reliable source to answer my question about promise.all():
What is(are) the correct scenario(s) to use promise.all()
OR
Are there any best practices to use promise.all()? Should it be ideally used only if all of the promise objects are of the same or similar types?
The only one I could think of is:
Use promise.all() if you want to resolve the promise only if all of the promise objects resolve and reject if even one rejects.
I'm not sure anyone has really given the most general purpose explanation for when to use Promise.all() (and when not to use it):
What is(are) the correct scenario(s) to use promise.all()
Promise.all() is useful anytime you have more than one promise and your code wants to know when all the operations that those promises represent have finished successfully. It does not matter what the individual async operations are. If they are async, are represented by promises and your code wants to know when they have all completed successfully, then Promise.all() is built to do exactly that.
For example, suppose you need to gather information from three separate remote API calls and when you have the results from all three API calls, you then need to run some further code using all three results. That situation would be perfect for Promise.all(). You could so something like this:
Promise.all([apiRequest(...), apiRequest(...), apiRequest(...)]).then(function(results) {
// API results in the results array here
// processing can continue using the results of all three API requests
}, function(err) {
// an error occurred, process the error here
});
Promise.all() is probably most commonly used with similar types of requests (as in the above example), but there is no reason that it needs to be. If you had a different case where you needed to make a remote API request, read a local file and read a local temperature probe and then when you had data from all three async operations, you wanted to then do some processing with the data from all three, you would again use Promise.all():
Promise.all([apiRequest(...), fs.promises.readFile(...), readTemperature(...)]).then(function(results) {
// all results in the results array here
// processing can continue using the results of all three async operations
}, function(err) {
// an error occurred, process the error here
});
On the flip side, if you don't need to coordinate among them and can just handle each async operation individually, then you don't need Promise.all(). You can just fire each of your separate async operations with their own .then() handlers and no coordination between them is needed.
In addition Promise.all() has what is called a "fast fail" implementation. It returns a master promise that will reject as soon as the first promise you passed it rejects or it will resolve when all the promises have resolved. So, to use Promise.all() that type of implementation needs to work for your situation. There are other situations where you want to run multiple async operations and you need all the results, even if some of them failed. Promise.all() will not do that for you directly. Instead, you would likely use something like Promise.settle() for that situation. You can see an implementation of .settle() here which gives you access to all the results, even if some failed. This is particularly useful when you expect that some operations might fail and you have a useful task to pursue with the results from whatever operations succeeded or you want to examine the failure reasons for all the operations that failed to make decisions based on that.
Are there any best practices to use promise.all()? Should it be
ideally used only if all of the promise objects are of the same or
similar types?
As explained above, it does not matter what the individual async operations are or if they are the same type. It only matters whether your code needs to coordinate them and know when they all succeed.
It's also useful to list some situations when you would not use Promise.all():
When you only have one async operation. With only one operation, you can just use a .then() handler on the one promise and there is no reason for Promise.all().
When you don't need to coordinate among multiple async operations.
When a fast fail implementation is not appropriate. If you need all results, even if some fail, then Promise.all() will not do that by itself. You will probably want something like Promise.allSettled() instead.
If your async operations do not all return promises, Promise.all() cannot track an async operation that is not managed through a promise.
Promise.all is for waiting for several Promises to resolve in parallel (at the same time). It returns a Promise that resolves when all of the input Promises have resolved:
// p1, p2, p3 are Promises
Promise.all([p1, p2, p3])
.then(([p1Result, p2Result, p3Result]) => {
// This function is called when p1, p2 and p3 have all resolved.
// The arguments are the resolved values.
})
If any of the input Promises is rejected, the Promise returned by Promise.all is also rejected.
A common scenario is waiting for several API requests to finish so you can combine their results:
const contentPromise = requestUser();
const commentsPromise = requestComments();
const combinedContent = Promise.all([contentPromise, commentsPromise])
.then(([content, comments]) => {
// content and comments have both finished loading.
})
You can use Promise.all with Promise instance.
It's hard to answer these questions as they are the type that tend to answer themselves as one uses the available APIs of a language feature. Basically, it's fine to use Promises any way that suits your use case, so long as you avoid their anti-patterns.
What is(are) the correct scenario(s) to use promise.all()
Any situation in which an operation depends on the successful resolution of multiple promises.
Are there any best practices to use promise.all()? Should it be ideally used only if all of the promise objects are of the same or similar types?
Generally, no and no.
I use promise.all() when I have to do some requests to my API and I don't want to display something before the application loads all the data requested, so I delay the execution flow until I have all the data I need.
Example:
What I want to do I want to load the users of my app and their products (imagine that you have to do multiple requests) before displaying a table in my app with the user emails and the product names of each user.
What I do next I send the requests to my API creating the promises and using promise.all()
What I do when all the data has been loaded Once the data arrives to my app, I can execute the callback of promises.all() and then make visible the table with the users.
I hope it helps you to see in which scenario makes sense to use promises.all()
As #joews mentioned, probably one of the important features of Promise.all that should be explicitly indicated is that it makes your async code much faster.
This makes it ideal in any code that contains independent calls (that we want to return/finish before the rest of the code continues), but especially when we make frontend calls and want the user's experience to be as smooth as possible.
async function waitSecond() {
return new Promise((res, rej) => {
setTimeout(res, 1000);
});
}
function runSeries() {
console.time('series');
waitSecond().then(() => {
waitSecond().then(() => {
waitSecond().then(() => {
console.timeEnd('series');
});
});
});
}
function runParallel() {
console.time('parallel');
Promise.all([
waitSecond(),
waitSecond(),
waitSecond(),
]).then(() => {
console.timeEnd('parallel');
});
}
runSeries();
runParallel();
I tend to use promise all for something like this:
myService.getUsers()
.then(users => {
this.users = users;
var profileRequests = users.map(user => {
return myService.getProfile(user.Id); // returns a promise
});
return Promise.all(profileRequests);
})
.then(userProfilesRequest => {
// do something here with all the user profiles, like assign them back to the users.
this.users.forEach((user, index) => {
user.profile = userProfilesRequest[index];
});
});
Here, for each user we're going off and getting their profile. I don't want my promise chain to get out of hand now that i have x amount of promises to resolve.
So Promise.all() will basically aggregate all my promises back into one, and I can manage that through the next then. I can keep doing this for as long as a like, say for each profile I want to get related settings etc. etc. Each time I create tonnes more promises, I can aggregate them all back into one.
Promise.all-This method is useful for when you want to wait for more than one promise to complete or The Promise.all(iterable) method returns a promise that resolves when all of the promises in the iterable argument have resolved, or rejects with the reason of the first passed promise that rejects.
2.Just use Promise.all(files).catch(err => { })
This throws an error if ANY of the promises are rejected.
3.Use .reflect on the promises before .all if you want to wait for all
promises to reject or fulfill
Syntax -Promise.all(iterable);
Promise.all passes an array of values from all the promises in the iterable object that it was passed.
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
var isCallFailed = false;
function myEndpoint1() {
return isCallFailed ? Promise.reject("Bohoo!") :Promise.resolve({"a":"a"});
}
function myEndpoint2() {
return Promise.resolve({"b":"b"});
}
Promise.all([myEndpoint1(), myEndpoint2()])
.then(values => {
var data1 = values[0];
var data2 = values[1];
alert("SUCCESS... data1: " + JSON.stringify(data1) + "; data2: " + JSON.stringify(data2));
})
.catch(error => {
alert("ERROR... " + error);
});
you can try another case by making isCallFailed = true.
Use Promise.all only when you need to run a code according to the result of more than one asynchronous operations using promises.
For example:
You have a scenario like, You need to download 2000 mb file from server, and at the same time you are going to free the user storage to make sure it can save the downloaded file.
And you need to save only in case if the file is downloaded successfully and the storage space is created successfully.
you will do like this.
your first asynchronous operation
var p1 = new Promise(function(resolve, reject) {
// you need to download 2000mb file and return resolve if
// you successfully downloaded the file
})
and your second asynchronous operation
var p2 = new Promise(function(resolve, reject) {
// you need to clear the user storage for 2000 mb
// which can take some time
})
Now you want to save only when both of the promises resolved successfully, otherwise not.
You will use promise.all like this.
Promise.all([p1,p2]).then((result)=>{
// you will be here only if your both p1 and p2 are resolved successfully.
// you code to save the downloaded file here
})
.catch((error)=>{
// you will be here if at-least one promise in p1,p2 is rejected.
// show error to user
// take some other action
})
Promise.all can be used in a scenario when there is a routine which is validating multiplerules based on particular criteria and you have to execute them all in parallel and need to see the results of those rules at one point. Promise.all returns the results as an array which were resolved in your rule vaidator routine.
E.g.
const results = await Promise.all([validateRule1, validateRule2, validateRule3, ...]);
then results array may look like (depending upon the conditions) as for example: [true, false, false]
Now you can reject/accept the results you have based on return values. Using this way you won't have to apply multiple conditions with if-then-else.
If you are interested only Promise.all then read below Promise.all
Promise (usually they are called "Promise") - provide a convenient way to organize asynchronous code.
Promise - is a special object that contains your state. Initially, pending ( «waiting"), and then - one of: fulfilled ( «was successful") or rejected ( «done with error").
On the promise to hang callbacks can be of two types:
unFulfilled - triggered when the promise in a state of "completed
successfully."
Rejected - triggered when the promise in the "made in error."
The syntax for creating the Promise:
var promise = new Promise(function(resolve, reject) {
// This function will be called automatically
// It is possible to make any asynchronous operations,
// And when they will end - you need to call one of:
// resolve(result) on success
// reject(error) on error
})
Universal method for hanging handlers:
promise.then(onFulfilled, onRejected)
onFulfilled - a function that will be called with the result with
resolve.
onRejected - a function that will be called when an error reject.
With its help you can assign both the handler once, and only one:
// onFulfilled It works on success
promise.then(onFulfilled)
// onRejected It works on error
promise.then(null, onRejected)
Synchronous throw - the same that reject
'use strict';
let p = new Promise((resolve, reject) => {
// то же что reject(new Error("o_O"))
throw new Error("o_O");
});
p.catch(alert); // Error: o_O
Promisification
Promisification - When taking asynchronous functionality and make it a wrapper for returning PROMIS.
After Promisification functional use often becomes much more convenient.
As an example, make a wrapper for using XMLHttpRequest requests
httpGet function (url) will return PROMIS, which upon successful data loading with the url will go into fulfilled with these data, and in case of error - in rejected with an error information:
function httpGet(url) {
return new Promise(function(resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.onload = function() {
if (this.status == 200) {
resolve(this.response);
} else {
var error = new Error(this.statusText);
error.code = this.status;
reject(error);
}
};
xhr.onerror = function() {
reject(new Error("Network Error"));
};
xhr.send();
});
}
As you can see, inside the function XMLHttpRequest object is created and sent as usual, when onload / onerror are called, respectively, resolve (at the status 200) or reject.
Using:
httpGet("/article/promise/user.json")
.then(
response => alert(`Fulfilled: ${response}`),
error => alert(`Rejected: ${error}`)
);
Parallel execution
What if we want to implement multiple asynchronous processes simultaneously and to process their results?
The Promise class has the following static methods.
Promise.all(iterable)
Call Promise.all (iterable) receives an array (or other iterable object) and returns PROMIS PROMIS, which waits until all transferred PROMIS completed, and changes to the state "done" with an array of results.
For example:
Promise.all([
httpGet('/article/promise/user.json'),
httpGet('/article/promise/guest.json')
]).then(results => {
alert(results);
});
Let's say we have an array of URL.
let urls = [
'/article/promise/user.json',
'/article/promise/guest.json'
];
To download them in parallel, you need to:
Create for each URL corresponding to PROMIS.
Wrap an array of PROMIS in Promise.all.
We obtain this:
'use strict';
let urls = [
'/article/promise/user.json',
'/article/promise/guest.json'
];
Promise.all( urls.map(httpGet) )
.then(results => {
alert(results);
});
Note that if any of Promise ended with an error, the result will
Promise.all this error.
At the same time the rest of PROMIS ignored.
For example:
Promise.all([
httpGet('/article/promise/user.json'),
httpGet('/article/promise/guest.json'),
httpGet('/article/promise/no-such-page.json') // (нет такой страницы)
]).then(
result => alert("не сработает"),
error => alert("Ошибка: " + error.message) // Ошибка: Not Found
)
In total:
Promise - is a special object that stores its state, the current
result (if any), and callbacks.
When you create a new Promise ((resolve, reject) => ...) function
argument starts automatically, which should call resolve (result) on
success, and reject (error) - error.
Argument resolve / reject (only the first, and the rest are ignored)
is passed to handlers on this Promise.
Handlers are appointed by calling .then / catch.
To transfer the results from one processor to another using Channing.
https://www.promisejs.org/patterns/

How to add another parallel AJAX call to the promises chain

I'm writing an app which
makes an AJAX call to establish user location based on an IP
address, then
makes a second AJAX call to provide current weather data
for this location, then
shows this data in DOM
I've developed the following promises chain which successfully delivers the above:
getUserLocation()
.then(function(locationData) {
return getCurrentWeather(locationData);
}).then(function(currentWeatherData) {
return showCurrentWeather(currentWeatherData);
});
Now I need to add a further functionality to the app so that it:
makes an AJAX call to establish user location based on an IP
address, then
makes a second AJAX call to provide current weather data
for this location, and
makes a third (concurrent, parallel) AJAX call to provide weather forecast data for this location, then
shows the current weather data in DOM, and
shows the weather forecast data in DOM
Below is what I've been experimenting with, but it does not work. Would you know how to fix this? My objective is to find a solution that makes only one AJAX call to get user location and then uses this data in two further AJAX calls (returned from the getCurrentWeather and getWeatherForecast functions).
getUserLocation()
.then(function(locationData) {
getCurrentWeather(locationData);
getWeatherForecast(locationData);
}).then(function() {
showCurrentWeather(currentWeatherData);
showWeatherForecast(weatherForecastData);
});
UPDATE 1 - WORKING SOLUTION FOUND:
Thanks to the approach suggested by #ReedSpool, I've managed to develop a working code:
getUserLocation()
.then(function(locationData) {
return jQuery.when(
getCurrentWeather(locationData),
getWeatherForecast(locationData)
);
}).then(function(currentWeatherData, weatherForecastData) {
showCurrentWeather(currentWeatherData[0]);
showWeatherForecast(weatherForecastData[0]);
});
The solution includes the jQuery.when. I also had to add index values of 0 to the arguments passed to the showCurrentWeather and showWeatherForecast functions. This is because the returned JSON now includes additional information about the readyState and status. This was not happening with my initial scenario with only one AJAX call to the weather API.
If you're indeed using jQuery promises (I'm gathering from the tags on your question, since the code provided has no jQuery specific stuff), then you're looking for jQuery.when() Every complete promise library has a similar function to this (Q.all for example)
Notice in your first example, you return the result of getCurrentWeather(locationData). Returning a promise inside a promise callback makes the outer promise wait for the inner promise to resolve. To wait for two or more promises to resolve, use jQuery.when() like...
getUserLocation()
.then(function(locationData) {
return jQuery.when(
getCurrentWeather(locationData),
getWeatherForecast(locationData)
);
}).then(function(curretnWeatherData, weatherForecastData) {
showCurrentWeather(curretnWeatherData[0]);
showWeatherForecast(weatherForecastData[0]);
});
See the documentation here: https://api.jquery.com/jquery.when/

AngularJS - Do you return the promise or data from the service/factory?

In my controller, I use a method from a factory to update some data. For example, I'm trying to fetch an updated array of users. Should I be returning the promise itself from the factory? Or should I be returning the data from the promise (not sure if I phrased that correctly)?
I ask because I've seen it both ways, and some people say that the controller shouldn't have to handle whether the request was successful or if it failed. I'm specifically talking about the promise returned from $http in this case.
Or maybe in other words, should I be using the then() method inside the factory, or should I be using it in the controller after returning from the factory?
I've tried to handle the success and error callbacks (using the this() method) from within the service, but when I return the data to the controller, the users array is not properly updated. I'm assuming that's because of the request being async. So in the controller, it would look something like this:
vm.users = userFactory.getUsers();
If I handle the promise from within the controller, and set the users array within the then() method, it works fine. But this goes back to where I should be using then():
userFactory.getUsers().then(
function(data){
vm.users = data;
}, ...
Hopefully someone would be able to shed some light on this or provide some input. Thanks!
There's no way you can return the data from the factory (since it's an async call) without using either a callback approach (discouraged):
userFactory.prototype.getUsers = function(callback){
$http.get('users').then(function (response) {
callback(response.data);
});
};
Or the promise approach.
If you're worried about handling the errors on the controller, then worry not! You can handle errors on the service:
userFactory.prototype.getUsers = function(){
return $http.get('users').then(function(response) {
return response.data;
}, function(error) {
// Handle your error here
return [];
});
};
You can return the results of then and it will be chained. So things from service will execute and then, later on, Controller ones.
I have no problem with controller deciding what to do basing on response failing/succeding. In fact it lets you easily handle different cases and doesn't add a lot of overhead to the controller (controller should be as small as possible and focused on current task, but for me going different path whether request failed is the part of its task).
Anyway, in Angular HTTP requests are wrapped in promises internally (I remember that in the previous versions there was a way to automatically unwrap them), so returning from service/factory always returns a promise, which has to be resolved.
I prefer returning a promise from a service/factory because I tend to let other classes decide what to do with the response.

Categories

Resources