Calling Q Promise on the basis of conditional logic - node.js

Below is my condition
if abc is true
call async func1, func2
else
call async func1
function test(): Q.Promise<boolean> {
if(abc)
Q.all([func1,func2])
else
Q.all([func1])
//if failed throw reject reason all the way in the chain
}
As shown, it can be done using if and else clause, is there a better way to call promise conditionally?
How to throw back error from any one of the promises?

I would put promises in array and append new one depending on condition:
function test(): Q.Promise<Boolean[]> {
const promises = [func1()]
if (abc) promises.push(func2())
return Q.all(promises)
}
I corrected type signature a little, because Q.all resolves with array of values (Boolean in your case) from each underlying promises. You also need to call func1 and func2. And finally, don't forget to return from test function.

You are actually pretty close already:
function test() {
if(abc)
return Q.all([func1(),func2()])
else
return func1();
}
test().then(() => {
// do whatever
}).catch(err => console.log(err));
Make sure you always return the promises as they don't get chained otherwise.

Related

How to "wait" for a property that get its value from a callback function?

Here is my code in TypeScript:
private getInfoSystem = () => {
this.systemInfo = {
cpuSpeed: 0 ,
totalRam: os.totalmem(),
freeRam: os.freemem(),
sysUpTime: os_utils.sysUptime(),
loadAvgMinutes: {
one: os_utils.loadavg(1),
five: os_utils.loadavg(5),
fifteen: os_utils.loadavg(15),
}
}
si.cpuCurrentSpeed().then ((data)=> {
this.systemInfo.cpuSpeed = data.avg ;
});
return this.systemInfo;
};
The property "cpuSpeed" first initialized to Zero and then I call the method cpuCurrentSpeed() which use a callback function and I try to put the value in "cpuSpeed".
The problem is that the the data of cpuCurrentSpeed() is late and the return value not include the wanted value in "cpuSpeed".
Because you are using .then on the cpuCurrentSpeed call, I assume that it's returning a Promise and not using callbacks. If it's like this, you could make your method asynchronous and await it:
private getInfoSystem = async () => {
this.systemInfo = {
cpuSpeed: 0 ,
totalRam: os.totalmem(),
freeRam: os.freemem(),
sysUpTime: os_utils.sysUptime(),
loadAvgMinutes: {
one: os_utils.loadavg(1),
five: os_utils.loadavg(5),
fifteen: os_utils.loadavg(15),
}
}
this.systemInfo.cpuSpeed = (await si.cpuCurrentSpeed()).avg;
return this.systemInfo;
};
Please note, that in this case your method also returns a Promise of the type of the value of this.systemInfo afterwards (which then needs to be awaited again by the calling method).
Otherwise, you can only rely on the returning value of Promises or callbacks inside of the callback because of it's asynchronous nature.

How to do proper error handling with async/await

I'm writing an API where I'm having a bit of trouble with the error handling. What I'm unsure about is whether the first code snippet is sufficient or if I should mix it with promises as in the second code snippet. Any help would be much appreciated!
try {
var decoded = jwt.verify(req.params.token, config.keys.secret);
var user = await models.user.findById(decoded.userId);
user.active = true;
await user.save();
res.status(201).json({user, 'stuff': decoded.jti});
} catch (error) {
next(error);
}
Second code snippet:
try {
var decoded = jwt.verify(req.params.token, config.keys.secret);
var user = models.user.findById(decoded.userId).then(() => {
}).catch((error) => {
});
user.active = true;
await user.save().then(() => {
}).catch((error) => {
})
res.status(201).json({user, 'stuff': decoded.jti});
} catch (error) {
next(error);
}
The answer is: it depends.
Catch every error
Makes sense if you want to react differently on every error.
e.g.:
try {
let decoded;
try {
decoded = jwt.verify(req.params.token, config.keys.secret);
} catch (error) {
return response
.status(401)
.json({ error: 'Unauthorized..' });
}
...
However, the code can get quite messy, and you'd want to split the error handling a bit differently (e.g.: do the JWT validation on some pre request hook and allow only valid requests to the handlers and/or do the findById and save part in a service, and throw once per operation).
You might want to throw a 404 if no entity was found with the given ID.
Catch all at once
If you want to react in the same way if a) or b) or c) goes wrong, then the first example looks just fine.
a) var decoded = jwt.verify(req.params.token, config.keys.secret);
b) var user = await models.user.findById(decoded.userId);
user.active = true;
c) await user.save();
res.status(201).json({user, 'stuff': decoded.jti});
I read some articles that suggested the need of a try/catch block for each request. Is there any truth to that?
No, that is not required. try/catch with await works conceptually like try/catch works with regular synchronous exceptions. If you just want to handle all errors in one place and want all your code to just abort to one error handler no matter where the error occurs and don't need to catch one specific error so you can do something special for that particular error, then a single try/catch is all you need.
But, if you need to handle one particular error specifically, perhaps even allowing the rest of the code to continue, then you may need a more local error handler which can be either a local try/catch or a .catch() on the local asynchronous operation that returns a promise.
or if I should mix it with promises as in the second code snippet.
The phrasing of this suggests that you may not quite understand what is going on with await because promises are involved in both your code blocks.
In both your code blocks models.user.findById(decoded.userId); returns a promise. You have two ways you can use that promise.
You can use await with it to "pause" the internal execution of the function until that promise resolves or rejects.
You can use .then() or .catch() to see when the promise resolves or rejects.
Both are using the promise returns from your models.user.findById(decoded.userId); function call. So, your phrasing would have been better to say "or if I should use a local .catch() handler on a specific promise rather than catching all the rejections in one place.
Doing this:
// skip second async operation if there's an error in the first one
async function someFunc() {
try {
let a = await someFunc():
let b = await someFunc2(a);
return b + something;
} catch(e) {
return "";
}
}
Is analogous to chaining your promise with one .catch() handler at the end:
// skip second async operation if there's an error in the first one
function someFunc() {
return someFunc().then(someFunc2).catch(e => "");
}
No matter which async function rejects, the same error handler is applied. If the first one rejects, the second one is not executed as flow goes directly to the error handler. This is perfectly fine IF that's how you want the flow to go when there's an error in the first asynchronous operation.
But, suppose you wanted an error in the first function to be turned into a default value so that the second asynchronous operation is always executed. Then, this flow of control would not be able to accomplish that. Instead, you'd have to capture the first error right at the source so you could supply the default value and continue processing with the second asynchronous operation:
// always run second async operation, supply default value if error in the first
async function someFunc() {
let a;
try {
a = await someFunc():
} catch(e) {
a = myDefaultValue;
}
try {
let b = await someFunc2(a);
return b + something;
} catch(e) {
return "";
}
}
Is analogous to chaining your promise with one .catch() handler at the end:
// always run second async operation, supply default value if error in the first
function someFunc() {
return someFunc()
.catch(err => myDefaultValue)
.then(someFunc2)
.catch(e => "");
}
Note: This is an example that never rejects the promise that someFunc() returns, but rather supplies a default value (empty string in this example) rather than reject to show you the different ways of handling errors in this function. That is certainly not required. In many cases, just returning the rejected promise is the right thing and that caller can then decide what to do with the rejection error.

Executing function when chain of promises resolves

I have written code using Q.reduce mechanism where function insertItemIntoDatabase(item) returns resolved promises.
items.reduce(function(soFar,item)
{
return soFar.then(function()
{
return insertItemIntoDatabase(item);
});
},Q());
Is there any possibilty to wait till chain is finished and then execute another function or I should chain those functions in some other way.
Thanks for help in advance
.reduce() will return the final value from the .reduce() loop, which in your case is a final promise. To execute something after the .reduce() chain and all its async operations are done, you just put a .then() handler on that final promise that is returned:
items.reduce(function(soFar,item) {
return soFar.then(function() {
return insertItemIntoDatabase(item);
});
},Q()).then(someOtherFunction);
The purpose of this pattern is exactly that: to return a promise for the result of the sequence. Written out (without reduce), it's exactly equivalent to the expression
Q()
.then(function() { return insertItemIntoDatabase(items[0]); })
.then(function() { return insertItemIntoDatabase(items[1]); })
.then(function() { return insertItemIntoDatabase(items[2]); })
…
You can simple add another .then() on it that will call your callbacks at the end of the chain.

Javascript function using promises and not returning the correct value

As a relative beginning in Javascript development, I'm trying to understand this problem I'm encountering in a function I've built that will be a part of the code to connect to a postgreSQL database.
In this function, I'm using the knex query builder method to check if a table exists in a remote database, and this method resolves to a boolean that indicates whether the string you specified matches with a table of the same name in the database. I've a provided a sample example of the knex syntax so people better understand the function.
knex.schema.hasTable('users').then(function(exists) {
if (!exists) {
return knex.schema.createTable('users', function(t) {
t.increments('id').primary();
t.string('first_name', 100);
t.string('last_name', 100);
t.text('bio');
});
}
});
I am trying to make my function return a boolean by using the .every Array method, which checks each array and should every index pass the condition defined, the .every method should return a true value, otherwise false. I've built a function which takes an array of schema keys, or names of tables, and passes it to the .every method. The .every method then uses the knex.schema.hasTable method to return a true or false.
My concern is that through many different configurations of the function, I have not been able to get it to return a correct value. Not only does it return an incorrect value, which may have something to do with .every, which I believe can return "truthey" values, but after defining the function, I will often get a "Function undefined" error when calling it later in the file. Here is a sample of my function - again I think it is moreso my poor understanding of how returns, promises and closures are working together, but if anyone has insight, it would be much appreciated.
var schemaTables = ['posts','users', 'misc'];
// should return Boolean
function checkTable() {
schemaTables.every(function(key) {
return dbInstance.schema.hasTable(key)
.then(function(exists) {
return exists;
});
});
}
console.log(checkTable(), 'checkTable function outside');
// console.log is returning undefined here, although in other situations,
I've seen it return true or false incorrectly.
Your function is not working properly for two reasons:
You are not returning the in the checkTable function declaration, so it will always return undefined.
You should write:
function checkTable() {
return schemaTables.every(function(key) {
return dbInstance.schema.hasTable(key)
.then(function(exists) {
return exists;
});
});
}
Anyway you will not get what you want just adding return. I'll explain why in the second point.
Array.prototype.every is expecting a truthy or falsey value syncronously but what the dbInstance.schema.hasTable returns is a Promise object (and an object, even if empty, is always truthy).
What you have to do now is checking if the tables exist asynchronously, i'll show you how:
var Promise = require("bluebird");
var schemaTables = ['posts', 'users', 'misc'];
function checkTable(tables, callback) {
// I'm mapping every table into a Promise
asyncTables = tables.map(function(table) {
return dbInstance.schema.hasTable(table)
.then(function(exists) {
if (!exists)
return Promise.reject("The table does not exists");
return Promise.resolve("The table exists");
});
});
// If all the tables exist, Promise.all return a promise that is fulfilled
// when all the items in the array are fulfilled.
// If any promise in the array rejects, the returned promise
// is rejected with the rejection reason.
Promise.all(asyncTables)
.then(function(result) {
// i pass a TRUE value to the callback if all the tables exist,
// if not i'm passing FALSE
callback(result.isFulfilled());
});
}
checkTable(schemaTables, function (result) {
// here result will be true or false, you can do whatever you want
// inside the callback with result, but it will be called ASYNCHRONOUSLY
console.log(result);
});
Notice that as i said before, you can't have a function that returns a true or false value synchronously, so the only thing you can do is passing a callback to checkTable that will execute as soon as the result is ready (when all the promises fulfill or when one of them rejects).
Or you can return Promise.all(asyncTables) and call then on checkTable it self, but i'll leave you this as exercise.
For more info about promises check:
The bluebird website
This wonderful article from Nolan Lawson
Thanks Cluk3 for the very comprehensive answer. I actually solved it myself by using the .every method in the async library. But yes, it was primarily due to both my misunderstanding regarding returns and asynchronous vs synchronous.
var checkTablesExist = function () {
// make sure that all tables exist
function checkTable(key, done) {
dbInstance.schema.hasTable(key)
.then(function(exists) {
return done(exists);
});
}
async.every(schemaTables, checkTable,
function(result) {
return result;
});
};
console.log(checkTablesExist());
// will now print true or false correctly

ES6 Promises - Calling synchronous functions within promise chain

I'm currently experimenting with promises and have a really basic question!
Within a promise chain, would it be bad practice to call a synchronous function? For example:
.then(function(results) {
if(checkIfResultInMemory(results) === true){
return getTotalFromMemory()
}
return results;
})
Or should my sync functions be refactored to return promises also?
Within a promise chain, would it be bad practice to call a synchronous
function?
No, it is not a bad practice at all. It is one of many expected and useful practices.
You are perfectly free to call either synchronous functions within the promise chain (from within .then() handlers) or asynchronous functions that then return a new promise.
When you return something from a .then() handler, you can return either a value (which becomes the resolved value of the parent promise) or you can return another promise (which chains onto the previous promise) or you can throw which works like returning a rejected promise (the promise chain becomes rejected).
So, that means you can call a synchronous function and get a value from it or call an async function and get another promise and then return either from the .then() handler.
All of these synchronous things are perfectly legal and each have their own objective. Here are some synchronous happenings in the .then() handler:
// modify resolved value
someAsync().then(function(val) {
return val + 12;
});
// modify resolved value by calling some synchronous function to process it
someAsync().then(function(val) {
return someSynchronousFunction(val);
});
// synchronously check the value and throw to change the promise chain
// to rejected
someAsync().then(function(val) {
if (val < 0) {
throw new Error("value can't be less than zero");
}
return val;
});
// synchronously check the value and return a rejected promise
// to change the promise chain to rejected
someAsync().then(function(val) {
if (val < 0) {
return Promise.reject("value can't be less than zero");
}
return val;
});
Here's a little example of an async operation that returns a promise followed by three synchronous .then() handlers and then outputting the final value:
function delay(t, val) {
return new Promise(function(resolve) {
setTimeout(function() {
resolve(val);
}, t);
});
}
function increment5(val) {
return val + 5;
}
delay(500, 10).then(increment5).then(function(val) {
return val - 3;
}).then(function(final) {
document.write(final);
});
Note: You only generally only want to use promises when you have or may have asynchronous operations because if everything is synchronous, then pure synchronous code is both faster to execute and easier to write. But, if you already have at least one async operation, you can certainly mix synchronous operations with that async operation and use promises to help structure the code.
A then callback function should:
return another promise
return a synchronous value (or undefined)
throw a synchronous error

Resources