I've a function, which returns a promise, inside that I call another function, and the status of this promise is based on the status of the inner promise.
Is there a way to shorthand this process. Look at the example below.
function foo(bar) {
var deferred = Q.defer();
switch (bar) {
case 'baz1':
deferred.resolve();
break;
case 'baz2':
deferred.reject();
break;
case 'this_is_how_i_do_it':
funReturningPromise().then(function (value) {
deferred.resolve(value);
}, function (err) {
deferred.reject(err);
});
break;
case 'can_we_do_it_like_this':
// can we do something like this, which will resolve or reject the deferred,
// based on the status promise returned by funReturningPromise().
// 'chain' is just a name
funReturningPromise().chain(deferred);
break;
}
return deferred;
}
Thanks,
It doesn't work as well for more complex functions, but in your example you could do something like:
case 'can_we_do_it_like_this':
return funReturningPromise();
You can also try adding your own promise.prototype.chain method if you're using only q promises.
If you return a value, throw an exception, or return a promise from inside any function managed by Q, particularly the callbacks given to then, the chained promise will “become” that value, exception, or promise.
var foo = Q.fbind(function (bar) {
switch (bar) {
case 'baz1':
return;
case 'baz2':
throw new Error("");
case 'this_is_how_you_can_do_it':
return funReturningPromise();
}
});
In this case, I’m using Q.fbind to guarantee that the return result is a promise, but if foo were called in the context of a promise handler, just like funReturningPromise, the fbind would be unnecessary. If you want to invoke a function immediately and get a promise for the result, you can also use fcall.
If you already have the deferred, then you can resolve it with another promise.
deferred.resolve(funReturningPromise())
Otherwise, what Kris said.
Related
My code is as follows: (node.js code)
'use strict';
var Promise = require('bluebird');
function promised()
{
return Promise.resolve();
}
function backgroundJob()
{
return Promise.resolve();
}
function doBackgroundJob()
{
// this is an intentional runaway promise.
backgroundJob()
.catch(function (err)
{
console.log('error', err);
});
}
function test()
{
return promised()
.then(function ()
{
doBackgroundJob();
return null; // without this, bluebird displays the warning
});
}
doBackgroundJob() does a background job, so it does not need to return a promise. But since it creates a promise, when the function is called in a then(), without an explicit return null in the then(), bluebird prints the following warning to the console. 'Warning: a promise was created in a handler but was not returned from it'.
This is somewhat unfair, since the caller does not need to know that the function uses a promise. How can I let bluebird to ignore the warning without return null in the then() in the caller?
I don't want to disable the warning, since it is quite useful.
One possibility is to add the background .then separately, and return only the base promise:
function test() {
const prom = promised();
prom.then(doBackgroundJob);
return prom;
}
while having doBackgroundJob return the promise (that proceeds to get discarded in this implementation):
function doBackgroundJob() {
// this is an intentional runaway promise.
return backgroundJob()
.catch(function(err) {
console.log('error', err);
});
}
allowing other consumers of doBackgroundJob to possibly use the promise it returns if needed.
It depends:
doBackgroundJob is doing something asynchronous, so it should return a promise as usual to let the caller know when it is finished. Even if it already does all error-handling and guarantees to only fulfill the promise. The caller, knowing that it returns a promise, would use return null in then callbacks to avoid the warning.
function doBackgroundJob() {
return backgroundJob().catch(console.error);
}
If the caller should not know what doBackgroundJobb is doing, you can create the promise asynchronously (so that Bluebird doesn't notice) and return nothing (so that the caller doesn't notice):
function doBackgroundJob() {
process.nextTick(() => {
// this is an intentional runaway promise.
backgroundJob().catch(console.error);
});
}
I'm using Node.js and q library.
I have a code that looks like this:
checkIfThingExists(function(idForAThing){
if(idForAThing){
updateThingData(idForAThing);
} else {
createThing(function(idForAThing){
updateThingData(idForAThing);
});
}
})
As you can see I need to call updateThingData(); twice.
Is there a way I can use promises to call updateThingData() just once, for example something like this? Of course this does not work and idForAThing is always undefined when the if statement runs:
checkIfThingExists(function(idForAThing){
if(!idForAThing){
createThing().then(function(newIdForAThing){
idForAThing = newIdForAThing
})
}
updateThingData(idForAThing);
})
Actually, what is happening is the .then method is a callback. It doesn't get called until after updateThingData is called.
You could instead create a promise chain that will resolve after it has the ID. Then chain the next .then callback to call updateThingData. Here is an example of that:
checkIfThingExists(function(idForAThing){
return Q.resolve() // or Promise.resolve if you were using the browser implementation
.then(function() {
if(!idForAThing) return createThing()
return idForAThing
})
.then(updateThingData)
})
You have to return in any case a promise.
So:
checkIfThingExists(function(idForAThing){
var promise
if(!idForAThing)
promise = createThing()
else
promise = Promise.resolve(idForAThing)
promise.then(function(id){
updateThingData(id)})
}
from
https://github.com/petkaantonov/bluebird/wiki/Promise-anti-patterns
what promise is he talking about?
myApp.factory('Configurations', function (Restangular, MotorRestangular, $q) {
var getConfigurations = function () {
//Just return the promise we already have!
return MotorRestangular.all('Motors').getList().then(function (Motors) {
//Group by Cofig
var g = _.groupBy(Motors, 'configuration');
//Return the mapped array as the value of this promise
return _.map(g, function (m) {
return {
id: m[0].configuration,
configuration: m[0].configuration,
sizes: _.map(m, function (a) {
return a.sizeMm
})
}
});
});
};
return {
config: getConfigurations()
}
});
where is a promise? for me it looks more like it's an anti pattern to use his pattern. I cannot see any promise in this code apart from the word then nothing makes me think of a promise.
So what does return MotorRestangular... actually return?
One thing to remember is that, both the resolve and reject function return a promise. In other word, it's already promisified for you. Even if you don't explicitly return something from the resolve, what you get is a promise that has been resolved with a value of undefined.
In your example, MotorRestangular.all('Motors').getList() returns a promise and in the resolve function, the first param in then, another resolved promise is returned which will get the result of _.map function as input. It's like:
function YourCtrl(Configurations) {
Configurations.getConfiguration().then(function(resultOfMap) {
// use resultOfMap here
})
}
Note:
Don't get confused by resolved and onFulfilled. They are kinda the same but the former is for deferred object and the latter is from Promise specification.
MotorRestangular.all('Motors').getList()
is a promise returned by MotorRestangular. You can easily chain promises between methods whenever you just make the called function return a promise.
I'm writing a test using Selenium and JavaScript. I'm new to both, and also new to functional programming and promises. I'm trying to create a function that needs to do 3 things:
Click on an input
Clear the input
SendKeys to input
My current function does not work:
var clearAndSendKeys = function(driver, elementIdentifier, sendKeys) {
var returnValue;
driver.findElement(elementIdentifier).then(function(inputField){
inputField.click().then(function() {
inputField.clear().then(function() {
returnValue = inputField.sendKeys(sendKeys);
});
});
});
return returnValue;
}
The function would then be called as for example:
clearAndSendKeys(driver, webdriver.By.id('date_field'), '14.09.2015').then(function(){
//Do stuff
});
I expected the variable returnValue to contain the promise from sendKeys. However the function clearAndSendKeys returns the undefined variable before sendKeys is ran. I assume this is because returnValue was never defined as a promise, and so the program does not know that it needs to wait for sendKeys.
How can I make my function clearAndSendKeys return the promise from sendKeys? I'd rather avoid having to add a callback to the clearAndSendKeys function.
Edit: Removed .then({return data}) from the code as this was a typo.
You have to return each promise from the .then callback:
var clearAndSendKeys = function(driver, elementIdentifier, sendKeys) {
return driver.findElement(elementIdentifier).then(function(inputField){
return inputField.click().then(function() {
return inputField.clear().then(function() {
return inputField.sendKeys(sendKeys);
});
});
});
}
The promise returned by .then will resolve to the same value as the value returned from the callback.
See Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference for why your current code does not work. Promises are asynchronous.
First of all its probably not the best idea to nest promises, completely defeating their main purpose of eliminating callback hell. then callback can return Thenable object that allows to create nice chains of async operations.
In this case you just need to store reference to input field available as a result of the first async operation in the scope of the main function and then create chain of async operations that can be returned from this function.
var clearAndSendKeys = function(driver, elementIdentifier, sendKeys) {
var inputFieldRef;
return driver.findElement(elementIdentifier)
.then(function(inputField){
inputFieldRef = inputField;
return inputField.click();
}).then(function() {
return inputFieldRef.clear();
}).then(function() {
return inputFieldRef.sendKeys(sendKeys);
});
}
I have the following function defined in a service, in which I use $http to get some data and set some of the fields of an object:
function getComplexObject () {
var complexObject = {
'A': null,
'B': null
}
$http.get('someURI').then(function(data) {
complexObject.A = data;
//Do some processing and set B
return complexObject;
})
};
So until now I've used a promise with the $http service but I don't know how to wrap the function with $q so that I can ultimately use it in the following manner:
//Using my function as a promise
myService.getComplexObject().then(function (data) {
this.complexObject = data;
})
I've searched for tutorials on angular promises but most of them simply explain what a promise is or do something similar to what I already did, I'm guessing what I want to do is possible but I can't find the right syntax or the right tutorial.
Just put return in front of the $http.get(...).then(...) chain, i.e.
return $http.get(...).then(...);
This will ensure that the result of getComplexObject is a promise that will (when its resolved) contain the value of complexObject.
That is exactly what .then is designed for - it takes the promise from $http.get() and returns a new promise that will ultimately be resolved with its own return value instead of the original one.
FWIW, I'd put the declaration of complexObject inside the .then call - there's no need for it to be in the outer scope and it'll inadvertently cause a closure over that variable.
NB: Also, be careful about using this in your final callback - it may not be what you think it is!
You could return a promise and resolve if later (see: https://docs.angularjs.org/api/ng/service/$q).
function getComplexObject () {
var deferred = $q.defer();
var complexObject = {
'A': null,
'B': null
}
$http.get('someURI').then(function(data) {
complexObject.A = data;
//Do some processing and set B
deferred.resolve(complexObject);
});
return deferred.promise;
};