Difference between $q.resolve() vs deferred.resolve() - AngularJS - javascript

I need to return a customized response in a promise, from an $http call, so I can chain further calls. I have two implementations available. Can someone explain the difference between two, and argue if one is better?
In fooService.js
Implementation #1
function foo() {
var deferred = $q.defer();
return $http.get('some-http-url')
.then(function(response) {
var data = response.data.Data;
// Some manipulation on data
deferred.resolve(data);
return deferred.promise;
});
}
Implementation #2
function foo() {
return $http.get('some-http-url')
.then(function(response) {
var data = response.data.Data;
// Some manipulation on data
return $q.resolve(data);
});
}
And then in FooController.js
fooService.foo().then(function(response) {
// Do something
});
P.S. Some links, that can give me a better understanding are welcome.
**************UPDATE 4th October, 2017**************
If I modify my function foo() like this
Implementation #1
function foo() {
var deferred = $q.defer();
if(/*some condition*/) {
deferred.resolve('data');
return deferred.promise;
}
else {
deferred.reject('error');
return deferred.promise;
}
}
Implementation #2
function foo() {
if(/*some condition*/)
return $q.resolve('data');
else
return $q.reject('error');
}
Which is the preferred way?

You don't need $q here at all, because $http already returns a promise.
Just return data in .then() and it will be available for the next .then() in the chain:
function foo() {
return $http.get('some-http-url')
.then(function(response) {
return response.data.Data;
});
}
The way you are doing your implementation is called deferred antipattern, more info in this answer.

Related

AngularJS: obtain underlying progression of an "asynchronous" call via promises

So, we currently have something like this at for asynchronous petitions to a backend.
First: a GenericApi for all the aplications
get: function (url) {
return api_bridge ({
execute: function (auth_headers) {
return $q.resolve($http.get(vm.urlBase + url, {headers: auth_headers}));
}
}).then(handlerSuccessResponse, handlerErrorResponse);
}
and then handler methods
//error
function handlerErrorResponse(response) {
return $q.reject(response);
}
//success
function handlerSuccessResponse(response) {
if (response.isAsync) {
return asyncStatus(response.taskId);
} else {
return $q.resolve(response);
}
}
Success got the key here, since if it is an async method, just recursively calls this method:
function asyncStatus(id){
return getAsyncStatus(id).then(function(response){
if (response.progress < 100){
return asyncStatus(id);
} else {
return getAsyncResult(id);
}
});
}
which calls either of those:
getAsyncStatus: function(id){
return get('/async/status/' + id);
},
getAsyncResult: function(id){
return get('/async/result/' + id);
},
(which call the first method of this list again).
And this way we can do a getter in such a way we don't ever care what happens under the hood:
get("/myurl")
.then(successMethod)
.catch(errorMethod);
(This will work same way whether it is asynchronous or not)
But now we would like to upgrade this system to be able to make callbacks everytime an asyncStatus call is made. Ideally something like this:
get("/myurl")
.then(successMethod)
.catch(errorMethod)
.progression(progressMethod);
The obvious way would be to pass a method as an argument through all the chain and then call it in every iteration of getAsyncStatus, but that kind of defeats the purpose of all this which is having a black box under the hood no one needs to worry about, plus changing this would imply changing all the current existing methods.
To make it the closest possible to the example I guess I would have to do something with $q.defer().notify() but I can't seem to grasp the concept right. Doing this doesn't work:
get("/myurl")
.then(successMethod, null, progressMethod)
.catch(errorMethod);
I have no clue how to make it work.
Well, apparently api_bridge method was breaking the promise binding. Found the solution is doing this:
Generic get:
get: function (url) {
var dfr = $q.defer();
dfr.resolve( api_bridge ({
execute: function (auth_headers) {
return $q.resolve($http.get(vm.urlBase + url, {headers: auth_headers}));
}
}));
return dfr.promise.then(handlerSuccessResponse, handlerErrorResponse);
}
Handler methods (no change):
//error
function handlerErrorResponse(response) {
return $q.reject(response);
}
//success
function handlerSuccessResponse(response) {
if (response.isAsync) {
return asyncStatus(response.taskId);
} else {
return $q.resolve(response);
}
}
Recursive async method:
function asyncStatus(id){
var deferred = $q.defer();
var deferred.promise.then(null, null, angular.noop);
var deferred.notify("This is a notification");
deferred.resolve(getAsyncStatus(id).then(function(response){
if (response.progress < 100){
return asyncStatus(id);
} else {
return getAsyncResult(id);
}
}));
return deferred.promise;
}
which calls either of those (no change);
getAsyncStatus: function(id){
return get('/async/status/' + id);
},
getAsyncResult: function(id){
return get('/async/result/' + id);
},
And now we can do:
get("/myurl")
.then(successMethod, null, progressMethod)
.catch(errorMethod);
Callback progressMethod will be called everytime asyncStatus throws a notification.

In angular function not waiting to complete first function execution

my function didnt wait to complete earlier function execution and it is completing.
I have my code is that i am doing some thing wrong:
$scope.abc1 = function(){
var arrayJson = [{'name':'max','age':'12'},{'name':'tax','age':'16'}]
for(var i=0; i<arratJson.length;i++){
var getAddress = $scope.xyz(arratJson[i].name);
}
$scope.createBody();
};
$scope.createBody = function(){
//some more code here
};
$scope.xyz = function(name){
$http({
method: 'GET',
url: 'rest/address',
type:'json',
headers:{'action':'single','name':name},
}).success(function(response){
return response;
}).error(function(response){
});
};
so in this it is not waiting to get address instead of it moving down so how to wait finishing for loop and then call different function.
createBody function called before the $scope.xyz() function returns the value how to wait until loop finishes
This is expected due to asynchronous nature of execution. You should use callbacks to avoid this problem.
You should use the $q service.
first store all $http calls in an array and with $q.all(array) you create a promise that is resolved after all $http promises have resolved.
e.g:
$scope.abc1 = function(){
var arrayJson = [{'name':'max','age':'12'},{'name':'tax','age':'16'}]
var promises = [];
for(var i=0; i<arratJson.length;i++){
promises.push($scope.xyz(arratJson[i].name));
}
$q.all(promises).then($scope.createBody);
};
And on the resolve of this new promise you can call your createBody function.
For this to work You should also change success callback on the $scope.xyz to a then callback and return the promise.
e.g:
$scope.xyz = function(name){
return $http({
method: 'GET',
url: 'rest/address',
type:'json',
headers:{'action':'single','name':name},
}).then(function(response){
return response;
})["catch"](function(response){
});
};
UPDATE
If you don't care if all calls succeed, replace:
$q.all(promises).then($scope.createBody);
With:
$q.all(promises)["finally"]($scope.createBody);
PS: Keep in mind that in the finally callback you don't get the return values of every call, whereas in the then an array will be passed as argument in the callback function which holds in every position a return value of each $http call.
There are two way to achieve this
1)Use async:false
2)Need to use callback
choose your way and enjoy!
You should how promises works in javascript.
$http is an asynchronous function. You must return $http result in $scope.xyz function and use then, success, error function callbacks.
Example:
function xyz() {
return $http(...);
}
xyz().then(function(data) {
address = data.data.address; // in your json dto format
})
more info https://docs.angularjs.org/api/ng/service/$http
hope this helps!
regards
You can use Angular promises.
Include promise status to self created object with deferred value, that has valueOf and toString methods. Last two methods allow to use arithmetic, string and comparison operators.
Object with deferred value:
var DeferredValue = function(initial){
var self = this;
self._value = initial;
var deferred = $q.defer();
self.$promise = deferred.promise;
self.$resolved = false;
self.$resolve = function(value){
deferred.resolve(value);
}
self.$promise.then(function(v){
self._value = v;
deferred = null;
self.$resolved = true;
delete self.$resolve;
return self.$promise;
});
}
DeferredValue.prototype = {
constructor: DeferredValue,
valueOf: function(){
return this._value
},
toString: function(){
return this._value.toString()
}
}
Return this object in your ASYNC function, and resolve them after retrieving data:
var getValue = function(){
var value = new DeferredValue();
$timeout(function(){
value.$resolve(Math.floor(Math.random() * 10))
},1500);
return value;
}
Plunker example

How to call a function containing chained promises

I am chaining multiple asynchronous function calls using promises and the Q js library. My current code looks like this:
function user() {
getID()
.then(getName);
}
function getID() {
var deferred = Q.defer();
asyncCall(arg, function(data) {
deferred.resolve(data);
});
return deffered.promise;
}
function getName(ID) {
var deferred = Q.defer();
asyncCall2(arg, function(data) {
deferred.resolve(data);
});
return deffered.promise;
}
I am trying to call user() from a different location and have it return the result of getName but am not sure how to do this.
just return the value (which is a promise itself):
function user() {
return getID().then(getName);
}
and later you can use it as the rest of your code:
user().then(function(result) {});

How to use $q.deffer to chain ajax requests?

I need to do this: browser have to make N requests to the server, requests mustn't be async, next requests are starting after previous requests will stop.
I can write some function A with for i < N i++ and calling this function A again recursively to do this, but it is not beautifull at all. Also, this called callback hell. I want some more beautifull solution.
I found deffered objects. Some says, it can help me to escape callback hell. I want something like this. setTimeout there is imitate one async request:
function foo1(some) {
debugger;
setTimeout(function foo1async() {
debugger;
deffered.resolve();
}, 500);
return deffered.promise;
}
function foo2(some) {
debugger;
setTimeout(function foo2async() {
debugger;
deffered.reject();
}, 500);
return deffered.promise;
}
function foo3() {
debugger;
setTimeout(function foo3async() {
debugger;
deffered.resolve();
}, 500);
return deffered.promise;
}
var deffered;
function doChain() {
debugger;
deffered = $q.defer();
var promise = deffered.promise;
promise.then(foo1);
promise.then(foo2);
promise.then(foo3);
promise["finally"](function () {
debugger;
});
deffered.resolve();
}
I expect foo1 to be called, then foo1async will be called and resolve deffered object.
foo2 must be called, then foo2async is called.
3.Now I expect, that foo3 wouldn't start, because deffered is rejected in foo2async. After that I expect foo in finally section called.
Actually, I have this:
foo1, foo2 and foo3 are called. Then foo in finally section called. Then foo1async, foo2async and foo3async funtions are called.
How I can get what I am expecting?
Actually, I will have something like this:
for(var i = 0; i < N; i++) {
(function (iter) {
promise.then(function () {
foo(iter);
});
})(i);
}
You got a few things wrong here.
First, you use a deferred to convert a callback-based async function into a promise-based - but each one needs its own deferred.promise and thus its own deferred. Actually, I prefer to use the $q constructor instead:
function fooN(input){
return $q(function(resolve, reject){
setTimeout(function(){
resolve(input + "; some more data");
}, 500);
});
}
(you could use var deferred = $q.defer() as well)
fooN now returns a promise, so you don't need to use $q.defer() anymore.
In fact, if the async function already was promise-based, like $timeout or $http, then you wouldn't have needed a deferred at all, for ex:
function fooN(input){
return $timeout(function(){
return input + "; some more data";
}, 500);
})
So, let's assume that foo1, foo2 and foo3 are implemented like fooN - all returning promises.
To make the calls sequential, you would need to chain promises - not to attach multiple handlers to the some root promise.
I'll break it down for you:
function doChain(){
var foo1Promise = foo1();
var foo2AfterFoo1Promise = foo1Promise.then(foo2);
var foo3AfterFoo2Promise = foo2AfterFoo1Promise.then(foo3);
var promise = foo3AfterFoo2Promise.then(function(finalData){
return doSomeProcessing(finalData); // if needed
});
promise.catch(function(error){
// "rethrow", if can't handle
return $q.reject({msg: "Some error occurred"});
})
return promise;
}
Or, the same, more concise:
function doChain(p){
return foo1(p)
.then(foo2)
.then(foo3)
.then(function(finalData){
return doSomeProcessing(finalData);
})
.catch(function(error){
return $q.reject({msg: "Some error occurred"});
});
}
A "promised" return value of each function is an input to the next chained function.
You can use $q.all method. For instance:
var promises = [promise1, promise2, ...];
$q.all(promises).then(function () {
// do something
});
What happens now is that all foo* promises depend on the single promise; when it gets resolved all are triggered. In ASCII art the dependencies are:
┎ foo1
promise ╁ foo2
┖ foo3
What you want is:
function doChain() {
foo1()
.then(foo2)
.then(foo3)
;
}
No need for the extra promise. No callback hell either!

Asynchronous Angular Promise and Variable Initialization

I have a factory that looks like such:
app.factory('thingFactory', function($http) {
var factory = {};
var things = [];
factory.refreshThings = function() {
return $http.post('/GetThings');
}
factory.initializeThings = factory.refreshThings()
.then(function(response) {
things = response.data;
}, function(response){
// some error handling code here...
});
factory.getThings = function() {
return things;
}
return factory;
}
and a controller
app.controller('myController', function($scope, thingFactory) {
$scope.things = thingFactory.getThings();
}
Because of the asynchronous nature of promises, and other collections being initialized (in addition to things), should I be concerned with getThings() returning an empty array, and thus, returning before the $http.post() call has resolved?
Is this a better alternative?
app.controller('myController', function($scope, thingFactory) {
$scope.things = []
thingFactory.initializeThings
.then(function(response) {
$scope.things = response.data;
}, function (response) {
// some error handling code here...
});
}
Is there a safe alternative, where I can get the controller to not think about the promise and just safely get the collection from the factory?
You're code is definitely going to be problematic. The factory will not be instantiated until it is used by a controller, so things will not be initialized until it is called by a controller, at which time initializeThings will get called right before you call getThings, which will likely return an empty array. Also, it's never a good idea to follow a "let's hope it's there" approach.
I see two approaches you can take: getThings accepts a callback as an argument or it returns a promise, which could look something like this:
Callbacks - I prefer callbacks over promises, but that's a personal thing. Also, I use NodeJS-inspired syntax:
var things; // no need to initialize array
// callback -> function (error, things) {}
factory.getThings = function (callback) {
if (things) {
return callback(null, things);
}
factory.refreshThings()
.then( function (response) {
things = response.data;
return callback(null, things);
}, function (reason) {
return callback(reason);
});
}
Promises - not the best syntax, but you get the idea
factory.getThings = function () {
var d = $q.defer();
// I'm sure there's a better way to do this, but setting
// this in a timeout will allow the promise to return so that
// you can try to return it.
$timeout( function () {
if (things) {
return d.resolve(things);
}
factory.refreshThings()
.then( function (response) {
things = response.data;
return d.resolve(things);
}, function (reason) {
return d.reject(reason);
});
});
return d.promise;
}
As a side note, if you're using a RESTful API, GET should be used to get information rather than POST.

Categories