How to call a function containing chained promises - javascript

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) {});

Related

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

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.

How to return deferred.resolve() from function in function

How do i get deferre.resolve from a function?
my Controller calls this:
service.getData().then(function(response){ //myFunc deferred response});
in Service:
var _getData = function (){
$http.get(url).success(function(response){
deferred.resolve(_myFunc(response.Message)); // or just myFunc doesnt matter
});
return deferred.promise; //it returns in the end of the function
}
and myFunc has also:
$http.get(url).success(function(response){
deferred.resolve(response);
});
return deferred.promise; // also my Func is returning
so i need the deferred resolve of myFunc, which is called in another func which is called in my controller.. and display it there
EDIT
I have return deferred.promise BUT it returns ONLY the first promise of the SERVICE function not myFunc, and i need the promise of myFunc
EDIT 2
Look also at Carson Drake's answer, it isn't anti-pattern!
You can actually reduce the two into one chained call if you want to simplify if.
var _getData = function(){
return $http.get(url).then(function(response1){
return $http.get(response1.data);
}).then(function(response2){
return response2;
});
UPDATE
Plunkr
You need to return defer.promise from the service of factory(whatever you are using)
var _getData = function (){
var deferred = $q.defer();
$http.get(url).success(function(response){
deferred.resolve(_myFunc(response.Message)); // or just myFunc doesnt matter
});
return deferred.promise;
}

How do you return a value from one class method to another when using Q/promises/asynchronous functions?

What is the best way to return a value from one class method to a different class method when using Q/promises/asynchronous functions?
Specifically, I have the following where ClassOne.myMethod() will call ClassTwo.test() to perform several asynchronous tasks (db updates, file writes, etc). I would like ClassTwo.test() to return something (in this example, "FOUR"). How do I do that when using promises and asynchronous calls?
I am doing this because I want ClassTwo to be a very generic set of methods that perform tasks that will be called by other classes (as not to reinvent the wheel each time).
E.g.,
var myClass = new ClassTwo();
ClassOne.prototype.myMethod = function(myClass) {
console.log('Returns: ', myClass.test());
};
ClassTwo.prototype.test = function() {
var one = function() {
var deferred = Q.defer();
console.log('ONE');
deferred.resolve();
return deferred.promise;
};
var two = function() {
var deferred = Q.defer();
console.log('TWO');
deferred.resolve();
return deferred.promise;
};
var three = function() {
var deferred = Q.defer();
console.log('THREE');
deferred.resolve();
return 'FOUR';
};
return one()
.then(two)
.then(three);
};
I think you are looking for something like the following. Note that I have wrapped all the calls to deferred.resolve() into callbacks from asynchronous functions (in this case process.nextTick), since that would be a more realistic use case then resolving the promise before returning it, and is, I assume what you would be doing with your asynchronous tasks. Also you declare a variable 'myClass' and also use the same identifier as a function parameter for 'myMethod'.I don't think that is really what you meant to do, so I have changed that in my example below.
var ClassTwo = function() {};
var ClassOne = function() {};
var Q = require('q');
ClassOne.prototype.myMethod = function(myClass) {
myClass.test().then(function(result) { // now test returns a promise
console.log('returns '+ result); // that we call .then() on
});
};
ClassTwo.prototype.test = function() {
var one = function() {
var deferred = Q.defer();
console.log('ONE');
process.nextTick(function() { deferred.resolve()});
return deferred.promise;
};
var two = function() {
var deferred = Q.defer();
console.log('TWO');
process.nextTick(function() { deferred.resolve()});
return deferred.promise;
};
var three = function() {
var deferred = Q.defer();
console.log('THREE');
process.nextTick(function() { deferred.resolve('FOUR')});
return deferred.promise;
};
return one()
.then(two)
.then(three)
};
(new ClassOne()).myMethod(new ClassTwo());

Chain promises with AngularJS

I have a service called paymentStrategy that get injected in my controller.
$scope.buy = function() {
paymentStrategy.buy()
.then(function(response) {
}
}
This buy method from paymentStrategy triggers several methods that needs to be called sequentially. When all the methods within buy() are done, then() needs to be called.
It is probably trivial but I am quite new to angular.
At the moment, buy().then() gets triggered straight after the init() methods.
I have the feeling we need to put all theses methods in a array of promises and apply $q.all().
Any help or suggestion would be greatly appreciated
angular.module('deps-app.payment.services', []).
factory('paymentStrategy', function($q) {
var deferred = $q.defer();
var ITEM_TO_PURCHASE = "test.beer.managed";
var promises = [];
var handlerSuccess = function(result) {
deferred.resolve(result);
};
var handlerError = function(result) {
deferred.reject(result);
};
_init = function() {
inappbilling.init(handlerSuccess, handlerError, { showLog:true });
return deferred.promise;
}
_purchase = function() {
inappbilling.buy(handlerSuccess, handlerError, ITEM_TO_PURCHASE);
return deferred.promise;
}
_consume = function() {
inappbilling.consumePurchase(handlerSuccess, handlerError, ITEM_TO_PURCHASE);
return deferred.promise;
}
return {
buy: function() {
_init();
.then(_purchase());
.then(_consume());
return deferred.promise;
}
}
});
If you need to chain promises in Angular sequentially, you can simply return the promises from one to another:
callFirst()
.then(function(firstResult){
return callSecond();
})
.then(function(secondResult){
return callThird();
})
.then(function(thirdResult){
//Finally do something with promise, or even return this
});
And if you want to return all of this as an API:
function myMethod(){
//Return the promise of the entire chain
return first()
.then(function(){
return second();
}).promise;
}
Make all methods atomar, by adding their own promises. In your code, the first resolve will complete the whole request.
If the methods have their own promise, you can chain them with ease.
angular.module('deps-app.payment.services', []).factory('paymentStrategy', function($q) {
var ITEM_TO_PURCHASE = "test.beer.managed";
_init = function() {
return $q(function (resolve, reject) {
inappbilling.init(resolve, reject, { showLog: true });
});
};
_purchase = function() {
return $q(function (resolve, reject) {
inappbilling.buy(resolve, reject, ITEM_TO_PURCHASE);
});
};
_consume = function() {
return $q(function (resolve, reject) {
inappbilling.consumePurchase(resolve, reject, ITEM_TO_PURCHASE);
});
};
return {
// In this case, you don't need to define a additional promise,
// because placing a return in front of the _init, will already return
// the promise of _consume.
buy: function() {
return _init()
.then(_purchase)
// remove () from inside the callback, to pass the actual method
// instead the result of the invoked method.
.then(_consume);
}
};
});

Returning a promise to the caller

I have a function HelloWorld where no promises is returned to the caller. I wonder if it is possible to have this function to adjust to return a promise.
For example:
function HelloWorld() {
// Do something here
return;
}
And in another function of my application I would like to do:
...
return HelloWorld()
.then( ... do something else here ... );
How to proceed to have this function return a promise?
function HelloWorld() {
var deferred = $.Deferred();
// demo
setTimeout(deferred.resolve, 1000);
// this is what you return:
return deferred.promise();
}
In HelloWorld :
var dfr = $.Deferred();
//some work with it
return dfr.promise();

Categories