I am new to promises but I am trying to get a function (which returns a number) to execute before continuing on. I have tried the following and none work:
var whatNumber = function(){
var defer = $q.defer();
myNumber.get().then(defer.resolve);
return defer.promise;
}
I also tried:
var whatNumber = function(){
var defer = $q.defer();
defer.resolve( myNumber.get());
return defer.promise;
}
And finally I tried it without promises:
var whatNumber = function(){
myNumber.get().then(function(result) {
return result;
});
}
Anyone have any ideas what I am doing wrong?
You should read about deffered antipattern In your case you can just return myNumber.get(); from the function:
var whatNumber = function(){
return myNumber.get();
}
Or, if you need to return specific property from the result:
var whatNumber = function(){
return myNumber.get().then(function(result) {
return result.data;
});
}
If you want to use the antipattern method (which you should avoid), then you need to resolve the promise and pass the parameters:
var whatNumber = function(){
var defer = $q.defer();
myNumber.get().then(function(result) {
defer.resolve(result);
});
return defer.promise;
}
whatNumber().then(function(result) {
console.log(result);
});
You are close, you just have your resolve aimed incorrectly from what I can see. You need to resolve the value you plan on using (the data)
var whatNumber = function(){
var defer = $q.defer();
myNumber.get().then(function(response){
defer.resolve(response.data)
});
return defer.promise;
}
Related
I would like to show off how much cleaner jQuery deferred objects can make the code instead of using the "callback hell".
I have no option to switch to Javascript's Promises.
Here is the "bad" code:
/* Callback Hell !? */
// Main
var stringToProcess = "1,2,3,4,5,6";
console.debug("Main Stack: start");
convertStringToArray(stringToProcess, function (convertedString){
convertToObject(convertedString, function(objectOfStrings){
resetObjectValues(objectOfStrings, function(object){
console.debug(object);
});
});
});
console.debug("Main Stack: end");
// Functions
function resetObjectValues(object, callback){
for(var key in object){
object[key] = "X";
}
setTimeout(function thirdcb(){
callback(object);
}, 500);
}
function convertToObject(string, callback){
var object = {};
string.map(function(current, index){
object[index] = current;
});
setTimeout(function secondcb(){
callback(object);
}, 500);
}
function convertStringToArray(string, callback){
var delimiter = ",";
var arrayString = string.split(delimiter);
setTimeout(function firstcb(){
callback(arrayString);
}, 500);
}
And thats how I tried to make it better:
/* Promise Heaven... */
// Main
var stringToProcess = "1,2,3,4,5,6";
console.debug("Main Stack: start");
var promise;
promise = convertStringToArray(stringToProcess);
promise.done(function(string){
promise = convertToObject(string);
promise.done(function(object){
promise = resetObjectValues(object);
promise.done(function(object){
console.debug(object);
})
})
});
console.debug("Main Stack: end");
// Functions
function resetObjectValues(object, callback){
var deferred = $.Deferred();
for(var key in object){
object[key] = "X";
}
setTimeout(function thirdcb(){
deferred.resolve(object);
}, 500);
return deferred.promise();
}
function convertToObject(string){
var deferred = $.Deferred();
var object = {};
string.map(function(current, index){
object[index] = current;
});
setTimeout(function secondcb(){
deferred.resolve(object);
}, 500);
return deferred.promise();
}
function convertStringToArray(string){
var deferred = $.Deferred();
var delimiter = ",";
var arrayString = string.split(delimiter);
setTimeout(function firstcb(){
deferred.resolve(arrayString);
}, 500);
return deferred.promise();
}
...sadly the .done() code looks almost as bad as the "hell" one. I cannot figure our how to chain the returns of promises/deferred properly. I saw tutorials where they do it without arguments to the function calls. But I have arguments to throw in - so how to get along with that?
The chaining of promises should look somewhat like this:
convertStringToArray(stringToProcess)
.then(function(string){
return convertToObject(string);
})
.then(function(object){
return resetObjectValues(object);
})
.then(function(object){
console.debug(object);
});
Basically each (callback) function returns a new promise, which can then be used to attach others handlers to it. That way you don't need the nesting of callbacks like in your code.
1 the value can not change in promise
for example
var t = function(s) {
var wait = function(dtd) {
var dtd = $.Deferred();
//new a Deferred object in function
var tasks = function() {
alert("complete!");
s = s + "hhh";
dtd.resolve(s); // change the state of deferred object
};
setTimeout(tasks, 5000);
// return promise object
return dtd.promise(s);
};
}
var s = "hhh";
$.when(t(s))
.then(function() {
alert(s);
}).then(function() {
alert(s);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
I can only got "hhh" instead of "hhhhhh"...
2
How to invoke promise chain with different values?like a.then(b(c)).then(f(d))
I put all values in a object and then pass it on chain...
The alert in your $.when is alerting the global variable not the resolve in tasks
Also , you never call wait() and tasks() doesn't return anything.
The return of the promise only returns to wait() which never gets called. Returning to the inner function does not return to the outer function
Also you have no arguments in then() to receive the resolved data.
In order to get data to the second then, you need to return something from the first one
var t = function (s) {
var wait = function () {
var dtd = $.Deferred();
//new a Deferred object in function
var tasks = function () {
alert("complete!");
s = s + "hhh";
dtd.resolve(s); // change the state of deferred object
};
setTimeout(tasks, 2000);
// return promise object
return dtd.promise();
};
// return the promise inside `wait`
return wait()
}
var s = "hhh";
$.when(t(s)).then(function (resolvedData) {
// return to the next then...just because we can
return resolvedData; // must return something if want to access it in next then
}).then(function(previousThenData) {
alert(previousThenData);// alert argument
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
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());
I've tried to find the answer to this and have started reading about promises / deferred, but when kicked off from somewhere else I don't know how to approach this.
angular.module('myapp.utilities').factory('codetabelService', ['Restangular', function(Restangular) {
var initialized = false;
var listtopopulate1 = [];
var listtopopulate2 = [];
var update = function() {
Restangular.all('codeTabel').getList()
.then(function(codetabellen) {
codetabellen.forEach(function(entry) {
//do some processing on return values
listtopopulate1.push(entry);
listtopopulate2.push(entry);
});
initialized=true;
});
};
return {
initialize: function() {
if (!initialized) {
update();
}
},
getListValuesType1: function() {
//How do I wait here for initialized to become true?
return listtopopulate1;
},
getListValuesType2: function() {
//How do I wait here for initialized to become true?
return listtopopulate2;
}
};
}]);
So what I'm trying to do is cache some values when my single page app starts.
On my root controller I call the initialize method which starts the async call to the backend.
When my views are being loaded and the controller sets the scope values to the result of getListValuesType1() the asynch call is sometimes not yet complete.
Because the async load was not triggered by the controller that called the method getListValuesType1() I'm not sure if promises will work here (I admit, I'm still new to this)
I found out you can put a timer on it, but this didn't seem right. It just feels there's a better solution out there.
Yes you can effectively use promise and promise caching to do this, one way you can achieve this by doing:-
angular.module('myapp.utilities').factory('codetabelService', ['Restangular', '$q', function(Restangular, $q) {
var initialized;//Use this to cache the promise
var listtopopulate1 = [];
var listtopopulate2 = [];
var _initialize = function() {
//If already initialized just return it which is nothing but the promise. This will make sure initialization call is not made
return initialized || (initialized= Restangular.all('codeTabel').getList()
.then(function(codetabellen) {
codetabellen.forEach(function(entry) {
listtopopulate1.push(entry);
listtopopulate2.push(entry);
});
//Note- You could even return the data here
}, function(){
//Just clean up incase call is a failure.
initialized = null;
//Just reject with something if you want to:-
//return $q.reject("SomeError")
}));
};
return {
initialize: function() {
return _initialize(); //Just return promise incase you want to do somthing after initialization
},
getListValuesType1: function() {
return _initialize().then(function(){ //return promise with a chain that resolves to the list
return listtopopulate1;
});
},
getListValuesType2: function() {
return _initialize().then(function(){ //return promise with a chain that resolves to the list
return listtopopulate2;
});
}
};
}]);
And while using it, you could do:-
codetabelService.getListValuesType1().then(function(list){
$scope.list1 = list;
});
With this you can even get rid of the initialize call from the contract and make the ajax call only during the first usage of getListX methods.
promises will work for this. You may need to refactor some things though.
angular.module('myapp.utilities').factory('codetabelService', ['Restangular', function(Restangular) {
var initialized = false;
var listtopopulate1 = [];
var listtopopulate2 = [];
var update = function() {
return Restangular.all('codeTabel').getList()
.then(function(codetabellen) {
codetabellen.forEach(function(entry) {
//do some processing on return values
listtopopulate1.push(entry);
listtopopulate2.push(entry);
});
initialized=true;
});
};
return {
initialize: function() {
if (!initialized) {
this.updatePromise = update();
}
},
getListValuesType1: function() {
//How do I wait here for initialized to become true?
return this.updatePromise.then(function() {
// you'll want to refactor the callee to handle a promise here
return listtopopulate1;
});
},
getListValuesType2: function() {
return this.updatePromise.then(function(){
// you'll want to refactor the callee to handle a promise here
//How do I wait here for initialized to become true?
return listtopopulate2;
});
//How do I wait here for initialized to become true?
}
};
}]);
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);
}
};
});