AngularJS - Promise vs then? - angularjs

I have 2 questions -
1) What is the difference between the "success" and "then"?
example - $http.get(url).then vs $http.get(url).success?
2) A promise means something that would be executed in the future, fine. I am not able to wrap my head on how this is difference from a function call. a promise call is executed when we make call using "$q.defer.resolve()". Isn't this a function call? so why can't this be a normal function, and executed with any other function call like foo()? Am i missing something special that a promise does!! ?

What is the difference between the "success" and "then"?
then() takes a single argument: the http response object. success() takes 4 arguments: the data of the response, the status of the response, the headers of the response, and the http config object. success() is thus easier to use when all you care about is the data returned. As said by New Dev, the returned value is different: then() returns a new promise for whatever is returned from its callback and allows you to return a new value and thus build a promise chain, whereas success() returns the original promise.
A promise means something that would be executed in the future
No, not really. A promise is the result of something you execute now, but for which the result is not immediately available. Since JavaScript is single-threaded, you can't just block and wait for the result, because that would completely freeze the application. So you just register a callback function that will be called, asynchronously, when the result is available. For example:
$http.get('/some/url')
immediately sends an HTTP request. But to get the result, we need to wait for the bytes to travel to the server, for the server to handle the request and send back a response, and for the response to travel to the browser. This could take several seconds. So what $http.get() returns immediately is a promise: i.e. an object which represents a future result (or, once the result has been received, a result that was once future).

.then returns a new promise.
.success returns the original promise. Another difference is that .success gets the response.data as an input parameter, whereas .then gets the response.
This is how it's implemented:
promise.success = function(fn) {
promise.then(function(response) {
fn(response.data, response.status, response.headers, config);
});
return promise;
};
You could use .success (and .error) to handle the respective outcome of $http, but without the ability to modify the data or to reject a promise (with return $q.reject()) given to the eventual consumer of the $http promise.
Here's an illustrative example of when one may use .success vs/with .then:
return {
getData: function(p1){
return $http.get(url, {p1: p1})
.success($log.log) // can use generic functions since there is
.error($log.error) // no requirement to return data
.then(function(response){
// here can massage the data into the output format
return response.data;
});
};
I recommend always using .then since it returns a new promise without .success and .error handlers; this avoids the chance of the API consumer using the $http-specific .success/.error thus inadvertently making the assumption that $http was used under the covers.

Related

Asynchronous call defer and promise chain

I stuck with ashync call chain. I tried google but couldn't found exact answer.
requirement is I have a method
callApi(){
I am calling 4 service that all are asynchronous.
I want to chain all the asynchronous calls so that I can do
defer.resolve only when all request are done
}
Any help would be great help.
Thanks in Advance.
You can just use $q.all(). It takes an array of promises and returns a promise, that will resolve when all promises in that array have resolved.
Example:
function callMultipleServices() {
return $q.all([
//Just some random functions returning promises...
someAsyncService(),
$http.get('http://google.de'),
someOtherAsyncService()
]) //.then(function(resultArray) { return doSomethingWith(resultArray) })
}
The returned promise will resolve with an array, containing the resolved values of the promises you passed in. If you want your promise to return a single value that is somehow derived from the service results, just add a .then that takes the results and somehow calculates your final promise result (as in the comment above)

the argument of the promise object's method then()'s callback function

I am new to angular, I did some research but still cannot find an answer...,
I have the following code:
promiseB = promiseA.then(function(result) {
return result + 1;
});
Why we can use result as the argument of the callback function? How the returned stuff of promiseA becomes result ?
Thanks everyone!
A promise is simply an object used to represent the pending activity, don't confuse it with the result of that activity.
The resolved value is passed to the success callback that was given to the .then() method. If promises are chained together then the value returned from that callback becomes the value passed to the next .then() (or if the value returned is also a promise the resolution of that promise is passed to the next .then()).
So in your particular example we don't know where result came from: whatever created promiseA simply ensured it resolved with that value. However we do know that promiseB will resolve with the value result+1 because that's what you returned.
When promiseA completes ("resolves"), it will call the function that you pass to the then() function, and pass the result into that function. So let's say I had a promise that is requesting information from a database query. Let's say it's going to (eventually) give me the phone number for a user. I'd set up my code to print that out like this:
myPromise.then(function(phoneNum) {
console.log(phoneNum);
});
The reason we can't just say var result = myPromise() is because a promise executes in a different flow that the rest of the code. We need to set up a function to handle the result when it's done
Check how using the $q service you can defer the promise returned and process in sucesives callbacks, the defer.promiseit's the key.
var promiseB = myService.response().then(function(result){
var defer = $q.defer();
defer.resolve(result);
return defer.promise;
});
promiseB.then(function(result){
console.log("In promise B ===>", result);
});
check this codepen: http://codepen.io/gpincheiraa/pen/ONjMrR?editors=0010

cannot access $scope variable out side a function

I have a variable defined in a controller:
app.controller('myController',['$scope','ajaxCall',function($scope,ajaxCall){
$scope.interviewer = {};
ajaxCall.get(/* A url */).then(function(response){
$scope.interviewer = response.data;
console.log($scope.interviewer);
});
console.log($scope.interviewer);
ajaxCall is a custom service which is used to make ajax calls. Inner console is working fine(i.e. it is showing the complete data) but the outer console is printing an empty object.Why?
Because the first A in AJAX means "Asynchronous".
The function passed to then() is executed asynchronously, a long time after the last console.log() line. It's executed once the response to the asynchronous HTTP request comes back from the server.
If it was synchronous, we wouldn't bother with promises and callback functions. We would just do
var response = ajaxCall.get(url);
But that isn't possible, so we do
ajaxCall.get(/* A url */).then(function(response){
which means: please send this request, and when the response is available, then call this function. I'll do plenty of other things in the meantime.

Angular and Meteor flicker on page load

I had an issue with and angular-meteor project flickering every time a state using the campaigns subscription, would load. By flickering, I mean the data was there, then it would go away and come back a half second later.
I added this to the resolve property of the state (using ui-router):
campaigns: ($q) => {
var deferred = $q.defer();
Meteor.subscribe('campaigns', {
onReady: deferred.resolve,
onStop: deferred.reject
});
return deferred.promise;
}
The flickering stopped, but I don't really understand this code. Can someone who understand angular break this resolve/defer situation down?
Just not sure why it worked. thanks.
$q is angular's implementation of promises.
in a very itty bitty nutshell, a promise has two callbacks that resolve when data is returned; a resolve function if the call succeeds and a reject if the call fails. whatever data it gets will be passed into these functions (essentially doing deferred.resolve(data) or deferred.reject(error)) . $q.defer() allows us to assign the resolution/rejections later.
meteor's subscribe function takes a few arguments. the string name of the collection, a function that returns an array of arguments to be passed to the collection, and an object/function. the object part of the final argument expects an "onReady" and "onStop" functions, and will execute those functions and pass along any data it gets. we pass in our callbacks here.
finally, we return the promise. resolve.campaigns will be a promise, which we can get the values from using the .then(successCallback, failureCallback) call. meteor handles this behind the scenes.

In Angular, what's the conceptual difference between the error and catch functions for promises?

I finally got Angular promise error handling down but it was counter-intuitive to me. I expected errors to be handled by the failure callback but instead I had to use a catch.
I don't quite understand conceptually why the catch is executed rather than the failure callback.
What I expected:
SomeAsyncService.getData().then(function (result) {
// The call is successful.
// Code in this block throws an error.
}, function (error) {
// I expected to handle errors here.
});
What eventually worked.
SomeAsyncService.getData().then(function (result) {
// The call is successful.
// Code in this block throws an error.
}).catch(function (error) {
// Where the error is actually caught.
});
If there is a more appropriate way to handle promise errors, let me know.
The second argument should be almost never be used literally in application code while also using the first. It is mostly about promise library interoperability between different implementations.
You should always use .catch unless you specifically have some weird corner case where you need .then(succcess, fail).
See The .then(success, fail) anti-pattern.
Also Q library (The one angular $q is based on) has similar section in their readme
I think you're slightly misunderstanding how promises work.
In your first code block there is only one promise object and it's SomeAsyncService.getData(). The errorCallback is not called here because that promise is resolved.
In the second code block there are actually 2 promise objects you're working with. Note that .then() "returns a new promise which is resolved or rejected via the return value of the successCallback, errorCallback". So what's happening is you're catching the error from the second promise returned from SomeAsyncService.getData().then(...).
By angularJS documentation for $q:
Methods
then(successCallback, errorCallback, notifyCallback) – regardless of
when the promise was or will be resolved or rejected, then calls one
of the success or error callbacks asynchronously as soon as the result
is available.
.....
catch(errorCallback) – shorthand for promise.then(null, errorCallback)
The two pieces of code you posted are identical.

Resources