How to break promise chain nested into another promise chain - node.js

I am unable to figure out how to break a nested promise chain into a main promise chain. Here is my code :
//Main Promise chain
let promiseMain = Promise.resolve(1)
.then(result => functionA())
.then(result => nestedChain()).catch((error) => {
console.log(error);
})
.then(result => functionC())
//chain error handler
function chainError(err) {
return Promise.reject(err)
};
function nestedChain()
{
stepOne()
.then(stepTwo, chainError)
.then(stepThreee, chainError)
.catch((error) =>
{
console.log(error);
return undefined;
});
}
function stepOne()
{
return chainError("error attempt : 1.00");
}
Once I go into the nestedChain where I throw an error in stepOne() I am able to break this nestedChain. Awesome!
The problem: It also breaks the main promise chain. So.. when it goes into nestedChain() and the error is thrown from stepOne(), functionC from the main promise chain will never be executed because the rejected promise from the nestedChain also break this chain.

You will have to attach with promises chain, do something like this
function nestedChain()
{
stepOne()
.then(stepTwo, chainError)
.then(stepThreee, chainError)
.catch ((error) => {
console.log(error);
return undefined;
})
}

Promise are implemented to wait for something which take more time. You just need to implement promise correctly.
For example if we have 3 function returning promise and one nested function also returning promise, this is how it's implemented:
functionA()
.then( result => {
return functionB();
})
.then( result => {
return nestedFunct();
})
.then( result => {
return functionC();
})
.then( result => {
console.log(result);
})
.catch( error => {
console.log(`Error in one of the above function`);
});
All the function are of format similar too
function functionA() {
return new Promise( (resilve, reject) => {
resolve('something');
// or
reject('Error');
});
}
Nested function can be like this
function nestedFunc() {
return functionD() // Return promise
.then( result => {
return functionE(); // return promise
})
.then( result => {
return functionF(); // return promise or value
});
}
Main promise chain is not affected by what individual function do as long as they keep returning promise. All individual function can have a local promise chain. Even if an error occurred in nested chain will be catched by catch() in main promise chain.

If i understood you correct, you need to catch error after nested chain promise
Promise.resolve().then(()=> {
console.log('A');
}).then(() => {
return Promise.resolve().then(() => {
console.log('step 1');
}).then(() => {
console.log('step 2');
throw new Error('Step 2 error');
});
}).catch((err) => {
console.log(err);
}).then(() => {
console.log('C');
});

Related

Handling nested promises

I am trying to reject a value inside a nested promise but it doesn't seem to actually reject it correctly. In the code below, when I get an error from promiseVariable, it doesn't reject with the error. In the promiseVariable.catch statement, I have reject(err). Shouldn't that reject with that error for the whole promise?
return new Promise((resolve, reject) => {
const user = anotherFunction();
if (!user) {
promiseVariable.then((data) => {
user = data;
}).catch((err) => {
reject(err)
})
}
resolve(user);
});
Because it will start the promiseVariable chain and jump over to resolve. In the .then, you should resolve there, or put an else.
return new Promise((resolve, reject) => {
const user = anotherFunction();
if (!user) {
promiseVariable
.then(resolve)
.catch(reject);
} else {
resolve(user);
}
});
It seems you're over-promising, if that's a word. You can just "await" for your other promise to complete.
Here, anotherFunction is a simulated Promise, where after 3 seconds it returns a valid object for your conditional if(!user).
You can try changing resolve({user: 1234}) with a false (or falsy) value to see its rejection.
function anotherFunction() {
return new Promise((resolve,reject) => {
setTimeout(() => resolve({user: 1234}), 3000)
});
}
async function mainFunction() {
const user = await anotherFunction();
return user || {error: 404};
}
mainFunction().then(result => console.log(result));

Catch errors in promise resolved with stream concatenation in node js

I need to catch errors thrown inside a stream event in promise resolution. Something like
function foo(){
return new Promise((resolve,reject) => {
resolve(res.pipe(transfomrStream).pipe(through2.obj(function(obj, enc, callback) {
on('end', ()=>{
await httpReq(...)
.then((crudRes) => assert.strictEqual(somerthing))
})
)
})
})
}
how could i catch assert failure? I've tried to return error inside the last pipe() or in function calling but i only get unhandled promise rejection
If you surround your code with a try catch you can at least see what your error is:
function foo(){
try{
return new Promise((resolve,reject) => {
resolve(res.pipe(transfomrStream).pipe(through2.obj(function(obj, enc, callback) {
on('end', ()=>{
await httpReq(...)
.then((crudRes) => assert.strictEqual(somerthing))
})
)
})
})
}
catch(e) {
console.log(e)
reject()
}
}
Also, if you have an await you cannot use .then(). And you will have to make your function async if you're doing await.

Unhandle rejection promise async await chain

I'm fairly new to async await in javascript so this question might be something I don't know.
I have this
async function foo(req, res, next) {
try {
await scan(req.params.stack);
res.send('ok');
} catch (err) {
res.status(500).send('fail');
}
}
async function scan(stack) {
try {
const libs = [1,2,3];
const promises = libs.map(async l => analyze(stack, l)
.catch((err) => { throw new Error(err); }));
return q.allSettled(promises)
.then((results) => {
const rejected = results.filter(r => r.state === 'rejected');
if (rejected.length === results.length) throw new Error('Failed');
return results;
})
.catch((err) => {
throw new Error(err);
});
} catch (err) {
throw new Error(err);
}
}
async function analyze(stack, libraries) {
try {
const config = await buildConfiguration(stack, libraries);
return await databaseInsertion(vulnsObject);
} catch (err) {
return Promise.reject('Error while trying to analyze libs');
}
}
Somehow I'm getting this wild warning and I don't know where I am not catching the error.
Of course, I'm making build configuration fail in order to test the error, but instead of having a normal flow cathing the error I got this:
(node:415) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 3): Error: Error while trying to analyze libs
Am I using async await good? Is there any pattern I should follow in order to chain async await?
The wild thing is that the foo function works well, meaning that the res.status.(500).send('fail'); works and I'm getting the response
When I was using native promises this error didn't appear.
I'm really stuck here
While using async-await scan function you were mixing .then() .catch() waterfall with await. async-await handles promises as good as .then(). So stick with one flow and try to mix both in one function or one inside another.
async foo(req, res, next) {
try {
await scan(req.params.stack);
res.send('ok');
} catch (err) {
res.status(500).send('fail');
}
}
async scan(stack) {
try {
const libs = [1,2,3];
// This libs.map functions return promise. then why not use await?
const promises = await libs.map(async l => analyze(stack, l);
// Again q.allSettled returns promise, use await here too
let results = await q.allSettled(promises);
const rejected = results.filter(r => r.state === 'rejected');
if (rejected.length === results.length) throw new Error('Failed');
return results;
}
// If any promise call reject function will be in catch
catch (err) {
throw new Error(err);
}
}
async function analyze(stack, libraries) {
try {
const config = await buildConfiguration(stack, libraries);
return await databaseInsertion(vulnsObject);
}
catch (err) {
console.log(err);
return null;
}
}
Calling an async function (here, analyze) would return a promise, which will resolve or reject according to the return value of the async function or whether an error was thrown.
Now, the analyze function is handling the error thrown but it will return a Promise.reject() when an error is thrown. A Promise.reject() is the unhandled rejection here, which is what the log is stating.
In terms of a synchronous function the equivalent will be
function sync() {
try {
// do something dangerous
} catch (ex) {
throw Error('Something bad happened'); // this error is still being thrown and nobody is handling it
}
}
To handle this error you can do the following when you are calling sync, wrap it in try and catch again
try {
sync();
} catch (ex) {
console.error(ex); // not gonna throw another exception, otherwise the program might crash
}
Now, the equivalent of this wrap for the analyze function will be using another async function, or better since calling async function will return a Promise, use the catch method of a Promise
analyze()
.then(() => console.log('My work is done here'))
.catch(ex => console.error(ex)); // NOTE: not throwing another exception
Even better would be to not return a rejection from catch in the first place, thus making analyze,
async function analyze(stack, libraries) {
try {
const config = await buildConfiguration(stack, libraries);
return await databaseInsertion(vulnsObject);
} catch (err) {
console.error(err); // not eating up good errors with something vague is always good
return null; // or something else to signify that insert failed
}
}
In the analyze() you are returning Project.reject() but analyze() is an async function. Therefor it resolves any value that you return and rejects any error you throw.
async function analyze(stack, libraries) {
try {
const config = await buildConfiguration(stack, libraries);
return await databaseInsertion(vulnsObject);
} catch (err) {
return Promise.reject('Error while trying to analyze libs');
}
}
So when the analyze function catches an error you are creating a rejection but then resolving the function. So Promise.reject('Error while trying to analyze libs'); is not being handled. Since async functions always return a promise that resolves with whatever you return and rejects whatever you throw, your analyze function is always going to resolve. Try doin this...
async function analyze(stack, libraries) {
try {
const config = await buildConfiguration(stack, libraries);
return await databaseInsertion(vulnsObject);
} catch (err) {
throw Error('Error while trying to analyze libs');
}
}
The other thing I see as a possible problem in this code is even though you pass the map(async func) an async function, it doesn't care. It won't wait for each function to complete before calling the next.
const promises = libs.map(async l => analyze(stack, l)
.catch((err) => { throw new Error(err); }));
return q.allSettled(promises)
.then((results) => {
const rejected = results.filter(r => r.state === 'rejected');
if (rejected.length === results.length) throw new Error('Failed');
return results;
})
.catch((err) => {
throw new Error(err);
});
There are two changes bellow
const promises = libs.map(async l => await analyze(stack, l)
.catch((err) => { throw new Error(err); }));
return q.allSettled( await promises)
.then((results) => {
const rejected = results.filter(r => r.state === 'rejected');
if (rejected.length === results.length) throw new Error('Failed');
return results;
})
.catch((err) => {
throw new Error(err);
});
I added an await before the analyze function and an await before passing the promises variable into q.allSettled().

NodeJS: understanding promise

I am starting to use promise in NodeJS. The requirement is to use these because of async calls. Here is the first code I wrote for promise.
function asyncFunc(data) {
return new Promise(
function(resolve, reject) {
try {
resolve(data);
} catch (err) {
reject("Custom Error");
}
});
}
//Usage:
asyncFunc('Sample String')
.then(result => { console.log(result); })
.catch(error => { console.log(error); });
//Output:
Sample String
null
//If I change the code to:
function asyncFunc(data) {
return new Promise(
function(resolve, reject) {
try {
reject("Custom Error");
} catch (err) {
resolve("Data");
}
});
}
//Output:
//Exception has occurred: string
//I get the above exception at line: reject("Custom Error");
So the question is "reject" can only be used from "catch" block? Why can't I raise "reject" event manually? What is the scenario "reject" is used? Can someone provide me a better example where I can use both "resolve" and "reject"?
You can use reject if you want, of course.
Let's suppose you have a function that resolves a promise if a person is adult, and rejects it if not.
You'd have something like this:
function asyncFunc(age) {
return new Promise((resolve, reject) => {
if(age >= 18) {
resolve(true);
} else {
// here you call reject manually outside of a catch block
reject(false);
// or
// reject(Error('not adult'));
}
});
}
usage:
asyncFunc(19).then(result => {
console.log(result); // true
})
.catch(error => {
console.log(error); // false or Error('not adult')
});
Probably you got something like (node:5009) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
Looks like you run your asyncFunc(..) in console. In this case node.js first execute your function after your hit Enter. Try to take your code to curly brackets like this:
{
asyncFunc('Sample String')
.then(result => { console.log(result); })
.catch(error => { console.log(error); });
}
In case of a try/catch block you usually reject at catch but you can also reject in try.
resolve and reject are basically callbacks for Promise. if you resolve it will got to the next chain if you reject it will break the chain.
So should use reject when an error occurs cause reject will break the promise chain.
For example.
Lets say you have a function that works with callback and you want to wrap it in a Promise like function. This function will check if user exists in database. If the User is found it will return true if not false and if there is an error in database (eg connection) it will reject.
function checkUserExist(id) {
return new Promise((resolve, reject) => {
checkUserExistInDatabase(id, function(result, error) {
if (error) {
reject(error);
}
if (result != null) {
resolve(true);
} else {
resolve(false);
}
})
});
}
function databaseError() {
return new Promise((resolve, reject) => {
reject();
})
}
var idsThatExist = [];
checkUserExist(1).then(function(exist) {
if (exist)
idsThatExist.push(1);
return checkUserExist(2)
}).then(function(exist) {
if (exist)
idsThatExist.push(2);
return databaseError(3)
}).then(function(exist) {
//WILL never Reach here
if (exist)
idsThatExist.push(3);
return checkUserExist(4)
}).then(function(exist) {
if (exist)
idsThatExist.push(4);
}).catch(function(err) {
//it will skip checkUserExist(4)
console.log('I got rejected after checked users:'
idsThatExist)
})
So the question is "reject" can only be used from "catch" block?
No, You can use reject anywhere. Catch isn't necessary to use reject
Why can't I raise "reject" event manually?
You can reject using creating new Promise() or static methods of Promise . See promiseUsingNew() and promiseUsingStaticMethod()
What is the scenario "reject" is used?
try/catch is used for error handling in synchronous programming. resolve & reject is for error handling in asynchronous programming operation instead of callbacks.
Can someone provide me a better example where I can use both "resolve" and "reject"?
'use strict';
function promiseUsingNew(marks) {
return new Promise((resolve, reject) => {
if (marks < 0 || marks > 100) {
return reject('Invalid marks');
}
if (marks >= 40) {
return resolve('You passed');
} else {
return resolve('You Failed');
}
});
}
function promiseUsingStaticMethod(marks) {
if (marks < 0 || marks > 100) {
return Promise.reject('Invalid marks');
}
if (marks >= 40) {
return Promise.resolve('You passed');
} else {
return Promise.resolve('You Failed');
}
}
// you can use promiseUsingNew(marks) or promiseUsingStaticMethod(marks)
promiseUsingNew(221).then((result) => {
console.log(result);
}).catch((error) => {
console.log(error);
});

Iterative promise if error

Below I have a function that returns a promise, where execAsyc will throw an error if the arrayItem is in valid, if it's invalid we move on to the next. Is there a iterative way to do this?
function performAction () {
return Promise.resolve()
.then(() => {
return execAsync(arrayItem[0])
})
.catch(() => {
return execAsync(arrayItem[1])
})
.catch(() => {
return execAsync(arrayItem[2])
})
}
Using Array#reduce should help you out:
function performAction() {
return arrayItem.reduce((prev, item) => {
return prev.catch(() => execAsync(item))
}, Promise.reject()) // start out with a rejected promise, so that execAsync is called for the first item in your array
}
This function returns a promise, that rejects if execAsync failed for all items in the array, or resolves with the result from execAsync for the first valid item.

Resources