In one of my applications I have a function which returns a Promise() and since this action requires updating an API, I am checking if the last function call asked to send the same information:
module.exports = function updateSidebar(sidebar) {
return new Promise(function(resolve, reject) {
if (sidebar === lastSidebar) {
// What to I do here?
} else {
// Application Logic
}
});
}
In this instance, would I reject() the Promise(), for giving me "invalid" data, or do I resolve() implying the action has been completed successfully? (which it has, just earlier)
Any advice is very welcome!
If you already have the result you want, then just resolve(result). That works perfectly fine and unless you consider this an error (in which case you would reject), then you should just resolve with some successful result.
module.exports = function updateSidebar(sidebar) {
return new Promise(function(resolve, reject) {
if (sidebar === lastSidebar) {
resolve(someSuccessfulResult);
} else {
// Application Logic
}
});
}
Related
requestReport()
.then(getReportData)
.then(checkReportStatus)
.then(handleData)
checkReportStatus = (data) => {
return new Promise((resolve, reject) => {
if(data.status === 'completed')
resolve(data)
else {
setTimeout(() => getReportData(), 1000)
}
So I make a report request first, then I need to check whether report was produced(status would turn into completed). If it is not completed yet , I need to call getReportData again. But I'm really confused with promises. My code is actually many lines and there is around 15 chainings going. What is the correct way to make call if report is not completed, so that when it becomes completed it can just continue from handleData?
edit1: typo
If getReportData() returns a promise that resolves with the data (which it appears to in your .then() chain) and doesn't need any input parameters from requestReport(), then you can just do this:
// utility function that returns a promise that resolves after a delay
// useful for inserting a delay into a promise chain
function delay(t) {
return new Promise(function(resolve) {
setTimeout(resolve, t);
});
}
requestReport()
.then(getReportData)
.then(checkReportStatus)
.then(handleData)
function checkReportStatus(data) {
if (data.status === 'completed') {
return data;
} else {
// retry after a delay
// add retry promise to the current promise chain
return delay(1000).then(getReportData);
}
}
If you need the results of requestReport() as arguments to getReportData(), then you will have pass that info into the promise chain so the retry on getReportData() can use it. You'd have to show us more detail (what data is returned from requestReport() and what data is needed by getReportData()) for us to make a specific recommendation on how best to do that.
checkReportStatus (data) => {
if (data.status === 'completed') {
return data;
} else {
// retry after a delay
delay(1000).then(checkReportStatus(data));
}
}
try call checkReportStatus(data).
I'm trying to create a web application using nodeJS and I'm stuck because of the asynchronous nature of nodeJS.
I have three different environments and based on user input from html form I should check if a user exists in the selected environment.
The html will have 3 check boxes and user can select any number of environments.
if(Dev_Environmnet){
getUserDatafromEnvironment(user,environment, function(callback1)){
if(callback1.error){
// User Does Not Exist Or credentials are wrong
}
else{
//get User API
}
});
}
if(PVS_Environmnet){
getUserDatafromEnvironment(user,environment, function(callback1)){
if(callback1.error){
// User Does Not Exist Or credentials are wrong
}
else{
//get User API
}
});
}
if(Prod_Environmnet){
getUserDatafromEnvironment(user,environment, function(callback1)){
if(callback1.error){
// User Does Not Exist Or credentials are wrong
}
else{
//get User API
}
});
}
once this is done I need those results from the callbacks to print it to another HTML page. this is what I need to show on the next page
DEV - API key gdeuysgdsgddiudgqwywdgAguiegdhsiw
pVS - user does not exist or credentials are wrong
Prod - APYI Key ugehdfiyugfugew%$%$udisfiuhygyig
I'm not able to get all these values at once. Can someone help me?
First, you can wrap your getUserDatafromEnvironment so that it returns a Promise:
function getUserDatafromEnvironmentP(flag, user, environment) {
if (!flag) return Promise.resolve(undefined); // method not selected
return new Promise(function(resolve) {
getUserDatafromEnvironment(user, environment, function(callback) {
resolve(!callback.error);
})
});
}
You can then call your three methods and pass them to Promise.all() which will wait until all three have completed and tell you the results:
let p1 = getUserDatafromEnvironmentP(Dev_Environmnet, user, environmnet);
let p2 = getUserDatafromEnvironmentP(PVS_Environmnet, user, environmnet);
let p3 = getUserDatafromEnvironmentP(Prod_Environmnet, user, environmnet);
let result = Promise.all([p1, p2, p3]).then(
function(results) {
// results[0 .. 2] will contain the three results
// undefined for "not used", false for "failed", true for "ok"
.. continue with processing here
})
);
// you can't do anything useful here because the above code is async
NB: generally I'd frown up using a resolve to indicate failure, but in this case it seems appropriate because of subsequent use of Promise.all().
Not sure what you mean by "get them at once" if you mean "know when all 3 async operations are completed", then there are a few ways you could do this, suggest you look into turning your async methods into promises (How do I convert an existing callback API to promises?) and use Promise.all or look at using async and await.
Based on your pseudo code, something like this.
// I assume that you need special functions to get the information
// from different providers.
function getUserFromPVS(user) {
return new Promise( (resolve, reject) => {
// special code to get user from PVS
return resolve(userdata);
});
}
function getUserFromDev(user) {
return new Promise( (resolve, reject) => {
// special code to get user from Dev
return resolve(userdata);
});
}
function getUserFromProd(user) {
return new Promise( (resolve, reject) => {
// special code to get user from Prod
return resolve(userdata);
});
}
// Converted the call to getUserDatafromEnvironment so it is a promise.
function getUserData(flagSelected, user, environment, req) {
return new Promise( (resolve, reject) => {
if (!flagSelected) return resolve(null); // Returns null if not selected
getUserDatafromEnvironment(user,environment, (cb) => {
if (cb.error) {
return resolve(null); // Return NULL instead of rejecting.
} else {
// Call to promise that return user information
// I assume you need different functions for
// each provider
return resolve( req(user) )
}
})
});
}
Promise.all([
getUserData( PVS_Environmnet, user, environment, getUserFromPVS ),
getUserData( Dev_Environmnet, user, environment, getUserFromDev ),
getUserData( Prod_Environmnet, user, environment, getUserFromProd ),
]).then( (results) => {
// results[0] has result from Dev or is null
// results[1] has result from PVS or is null
// results[2] has result from Prod or is null
}).catch(
(error) => console.error(error)
)
You should keep calls to the other checks inside callbacks from previous ones:
checkOne(someArgs, (callback) => {
let checkOneResult = true;
if (callback.error)
checkOneResult = false;
checkTwo(someArgs, (callback) => {
let checkTwoResult = true;
if (callback.error)
checkTwoResult = false;
//here I got result from both checks:
console.log(checkOneResult);
console.log(checkTwoResult);
});
});
I'm having an issue with a Node.js function. I'm fairly certain that it is just an issue with the function being asynchronous but I want to be sure. I am checking to see if a certain path that was entered by the user is valid by checking if it exists.
var directoryExists = exports.directoryExists = function(filePath) {
return new Promise(function(resolve, reject) {
if (fs.statSync(filePath).isDirectory()){
resolve("Valid");
} else {
reject("Invalid");
}
});
}
These are my calls to the function:
files.directoryExists(sourcePath).then((msg) => {
console.log(msg);
}).catch(function(){
console.error("Promise Rejected");
});
files.directoryExists(destPath).then((msg) => {
console.log(msg);
}).catch(function(){
console.error("Promise Rejected");
});
I'm very new to the whole concept of asynchronous programming and promises so this is becoming quite frustrating. Any help would be appreciated.
It's not really the asynchronous thing that's catching you out, although there's a change you can make to improve that.
statSync can throw an exception (if the path doesn't match anything, for instance); you're not handling that, and so when it throws, that gets converted into a rejection. If you looked at the argument you're getting in your catch handler, you'd see the exception that it raises.
The async improvement is that since you're using a Promise, there's no reason to use statSync. Just use stat so you don't tie up the JavaScript thread unnecessarily.
So something along the lines of:
var directoryExists = exports.directoryExists = function(filePath) {
return new Promise(function(resolve, reject) {
// Make the request asynchronous
fs.stat(filePath, function(err, data) {
// If there was an error or it wasn't a directory...
if (err || !data.isDirectory()) {
// ...reject
reject(err || new Error("Not a directory");
} else {
// All good
resolve(data);
}
});
});
};
Of course, you may choose to have it resolve with false if the thing isn't a directory or any of several other choices; this just gets you further along.
For instance, having an error still be a rejection, but resolving with true/false for whether something that exists is a directory; this provides the maximum amount of information to the caller but makes them work a bit harder if all they care about is true/false:
var directoryExists = exports.directoryExists = function(filePath) {
return new Promise(function(resolve, reject) {
// Make the request asynchronous
fs.stat(filePath, function(err, data) {
if (err) {
// Reject on error
reject(err);
} else {
// Return result on success
resolve(data.isDirectory());
}
});
});
};
or making it always resolve, with false if there's no match or there is a match but it's not a directory:
var directoryExists = exports.directoryExists = function(filePath) {
return new Promise(function(resolve) {
// Make the request asynchronous
fs.stat(filePath, function(err, data) {
resolve(!err && data.isDirectory());
});
});
};
Lots of ways for this function to behave, it's up to you.
I am new to JavaScript promises and I am trying to implement them into some PhoneGap code on an Android device. I want to log exceptions and it looks like exceptions are swallowed somewhere. See the sample code below. The exception thrown due to the call to the non-existent function "thiswillfail" does not show anywhere. I commented out the irrelevant code and added code to force the AddRecord promise to be called. The code checks if a record exists and, if not, return the AddRecord promise which is the error is. I am not using any 3rd party libraries. What am I doing wrong?
Edit: If I add another promise in the chain "DoSomethingWithRecord", this promise is called when the expectation is to skip to the catch.
function TestPromiseExceptionHandling() {
var record = null;
var CheckForRecord = function () {
return new Promise(function (resolve, reject) {
//getData(
// function (data) {
var data = "";
if (data != "") {
//record = new Record(data);
record = "existed";
resolve();
}
else return AddRecord();
// },
// function (err) {
// reject(new Error("An error occurred retrieving data, msg=" + err.message));
// });
});
};
var AddRecord = function () {
return new Promise(function (resolve, reject) {
thiswillfail();
//add record
var success = true;
record = "new";
if (success) resolve();
else reject(new Error("add record failed"));
});
};
var DoSomthingWithRecord = function () {
return new Promise(function (resolve, reject) {
alert(record);
resolve();
});
};
try {
CheckForRecord()
.then(DoSomthingWithRecord())
.catch(function (err) { alert(err.message);})
.then(function () { alert("done"); });
} catch (err) {
alert(err.message);
}}
You can't return from the promise constructor, when you do:
else return AddRecord();
Nothing will wait for AddRecord, instead, you want to resolve with AddRecord which will wait for it before resolving the promise:
else resolve(AddRecord());
However, if this is your code you can just return AddRecord() instead of using the promise constructor anyway. The promise constructor (new Promise) is mostly useful for converting non-promise APIs to promises and aren't supposed to be used with already promisified APIs. Use thens instead.
I'm new to Javascript and AngularJS and this one makes me scratch my head :/
Precondition
A REST Service providing my data from the backend
AngularJS 1.2.21 and Restangular 1.4.0
An AngularJS controller, that shall ask the service for a spiced up version of the provided
What I have
This is the method in question:
service.getSlices = function() {
Restangular.all('entries').getList().then(function(entries) {
//some rather complex modification of the backend data go here
//...
return resultOfModification; //this is what should be returned for getSlices();
})
//I want the resultOfModification to be returned here
};
The question
Bascially I would like to wait in getSlices() until the promise is resolved in order to return my resultOfModification only when it actually is calculated.
Additional scenario
I could also image to return a promise from getSlices() which would then provide the resultOfModification. However I fear I do not understand this well enough and / or am too frustrated / tired meanwhile.
Answers and any suggestions are welcome, especially pointers to good reading material. Thanks
You can't return it at that place as actual value, because Restangular is async (the function getSlices is left before the callback you pass to then is called). That's why Promise is used.
Even if it would be possible to make Restangular to be sync you shouldn't do that because this will block the browser until the data is requested which will be a bad user experience.
You should try to get into Promise as they where designed to look like sync code but behave async.
The thing you would need to change in your code is to add a return before the Restangular.all :
service.getSlices = function() {
return Restangular.all('entries').getList().then(function(entries) {
//some rather complex modification of the backend data go here
//...
return resultOfModification; //this is what should be returned for getSlices();
})
};
This will return the Promise that is return by the .then call. This Promise will resolve to resultOfModification as this is the vale you return form its callback.
That way you could use getSlices that way:
service.getSlices().then(function(modifiedData) {
});
Promises can be chained up:
(new Promise(function( resolve, reject){
setTimeout(function() {
resolve("some");
},200);
}))
.then(function(data) {
return data+' data';
})
.then(function(data) {
//here a Promise is return which will resovle later (cause of the timeout)
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(data+' !!!!!!');
},200);
});
})
.then(function(data) {
//this will have 'some data !!!!!!'
console.log(data);
});
Which would be the same as if you would write it that way:
var promiseA = new Promise(function( resolve, reject){
setTimeout(function() {
resolve("some");
},200);
});
var promiseB = promiseA.then(function(data) {
return data+' data';
})
var promiseC = promiseB.then(function(data) {
//here a Promise is return which will resovle later (cause of the timeout)
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(data+' !!!!!!');
},200);
});
});
var promiseD = promiseC.then(function(data) {
//this will have 'some data !!!!!!'
console.log(data);
});