Promise.try without bluebird - node.js

I am trying to re-create bluebird's promise.try function, is this essentially the same?
function promiseTry(callback) {
let error;
let value;
try {
value = callback();
} catch (e) {
error = e;
}
return new Promise((resolve, reject) => {
if (error) {
reject(error);
throw error;
}
resolve(value);
});
}
const x = promiseTry(() => {
throw new Error('hi');
});
How can I simply implement bluebird's Promise.try with a native node Promise?

This should be equivalent:
function promiseTry(callback) {
return new Promise((resolve, reject) => {
try {
resolve(callback())
} catch(e) {
reject(e);
}
});
}
const x = promiseTry(() => {
throw new Error('hi');
});
x.then(() => console.log("Promise resolved")).catch(err => console.log("Promise rejected:", err.message));
If you can use async/await, async functions have this behavior implicitly. Any synchronous exceptions thrown in an async function are converted into a promise rejection.

Related

Catch promise rejection in nested function

I have this repro: https://codesandbox.io/s/jolly-bogdan-k6ii4?file=/src/index.ts
code:
const wait = (timeoutMs: number) => {
let timeoutHandle: number | undefined;
const promise = new Promise((_resolve, reject) => {
timeoutHandle = setTimeout(() => {
reject(`wait timed out after ${timeoutMs} ms`);
}, timeoutMs);
});
return {
promise,
cancel: (): void => clearTimeout(timeoutHandle)
};
};
const waitBy = (timeoutMs: number) => {
const res = wait(timeoutMs);
return res;
};
const main = async () => {
try {
const { promise, cancel } = waitBy(3000);
} catch (error) {
console.log("failed on timeout");
}
// try {
// await promise;
// } catch (error) {
// console.log("timed out");
// }
};
main();
When this is ran in Node.js, the reject will throw after 3s, and blow up the whole process with an "unhandledRejection Error" - where can one catch this error to avoid an unhandledRejection Error, but allow it to propagate up to the catch inside the main function?
The problem is that you're not waiting for the promise to resolve before moving forward and the error is thrown then outside of the try block.
const main = async () => {
try {
const { promise, cancel } = waitBy(3000);
await promise // new code
} catch (error) {
console.log("failed on timeout");
}
// try {
// await promise;
// } catch (error) {
// console.log("timed out");
// }
};

Waiting for promises: NodeJS + Express [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 3 years ago.
How can I wrap an existing node.js api (an npm module: PythonShell) into a promise to make it synchronous. Here is my attempt (based on other similar questions):
new Promise(function(resolve, reject) {
PythonShell.run('./script.py', (err, results) => {
resolve(results); // no errors in this case
})
}).then(r => {
return r;
});
All inside a normal function. This returns a promise for some reason, I expect it to return the value of r.
It returns a promise because this is a Promise. You need to wait for the Promise to resolve by putting your code in the then or by using async/await. A Promise does not make your code synchronous.
For example
function run() {
return new Promise((resolve, reject) => {
PythonShell.run('./script.py', (err, results) => {
if (err) {
return reject(err)
}
return resolve(results);
})
})
}
async function main() {
const results1 = await run();
// Or
run().then((results2) => {
// Do something with results2 here, not outside out this block
})
}
main()
Create an async function/Promise to get the result from your script:
const getValue = () => {
return new Promise((resolve, reject) => {
PythonShell.run('./script.py', null, (err, results) => {
if(err) reject(err);
else resolve(results);
});
});
}
and the you can call it like:
getValue()
.then((r) => {
console.log("Result is => ", r);
// Do Something with r
})
.catch((e) => {
console.log("Error while fetching value: ", e);
});
Hope this helps :)

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().

logging errors in async functions

I have this code:
async function getURL() {
try {
await fetch("http://www.blah.com");
return 0;
} catch (err) {
return err;
}
}
getURL().then( result => {
if (result === 0) console.log("success");
else console.log(result);
});
The fetch will fail and the error is logged to the console. How do I rework the code so it uses async and try/catch everywhere? That is, I'm looking to avoid doing getURL().then for the sake of consistency.
EDIT:
For those downvoting me, await getURL() won't work as it's invalid syntax.
EDIT2:
Tried this but it didn't catch the error:
async function getURL() {
return await fetch("http://www.blah.com");
}
let result = async function() {return await getURL();}
try {
result();
} catch (e) {
console.log(e);
}
You can wrap your whole code inside an instantly executed async function like this:
// service.js
async function getURL() {
return await fetch("http://www.blah.com");
}
// your.module.js
(async function() {
// do things...
try {
let result = await getURL();
} catch (e) {
console.log(e);
}
// do things...
res.send({});
});
Every time you need to catch an error from promise, either using new Promise, async-await or generator you need to use .then() or you can do something like this another async-await.
async function getURL() {
try {
await fetch("http://www.blah.com");
return 0; // EDIT: just returning value which is success
} catch (err) {
return err; // EDIT: returning value not rejecting a promise
}
}
async function main () {
try {
let result = await getURL();
if (result === 0) console.log("success");
console.log(result); // EDIT: error will be print.
}
catch (err) { // EDIT: getURL() never rejects so always success.
console.log(err);
}
});
main();
This situation doesn't really occurs as while our main function in server-side or client-side are async and handling this for us.
Like using express:
app.post('/api', async (req, res) => {
try {
let result = await getURL();
res.send(async);
}
catch(err) {
res.send(err);
}
});
EDIT: asyn-await doesn't reject or resolve a call, just return a value. thus must be used carefully.
function fetch(url) {
return new Promise( (resolve, reject) => {
let x = Math.floor(Math.random() * Math.floor(9) + 1);
// 50-50 resolve or reject
if(x%2===0) return resolve(false); //resolve with `false` statement
reject(true); // reject with `true` still a reject
});
}
async function getURL() {
try {
await fetch("http://www.blah.com");
return 0; // if fetch resolve
} catch (err) { //only if fetch reject
return err;
}
}
async function main () {
try {
let result = getURL();
if (result === 0) console.log("success"); //getURL never reject any call
console.log(result);
}
catch (err) { // getURL doesnt reject
console.log(err);
}
};
main();
I realize now async functions always return a promise. Even if you throw an error it still gets wrapped up into a promise. Therefore using try/catch won't help. This is how I ended up writing the code:
async function getURL() {
return await fetch("http://fake");
}
getURL().then( () => console.log("success")).catch( (e) => console.log(e));

How to chain promise in array

I need help with ES6 Promises chaining in array processing.
How to process/define each item of array which goes into Promise.all method, when there is other async method inside resolve?
Here is simplified example:
function getData(data, callback) {
let groupPromises = data.map(row => {
var coordinates = getCoordinates(row);
return Promise.resolve({
"place": getPlaces(coordinates), //how to invoke this method
"data": row
};
});
Promise.all(groupPromises)
.then(groups => callback(groups))
.catch(err => console.log(err));
}
}
function getPlaces(coordinates) {
return new Promise(function(resolve, reject) {
if(coordinates == null) {
reject();
}
parameters = {
location: [coordinates.latitude, coordinates.longitude],
rankby: "distance",
};
googlePlaces.searchPlace(parameters, function (error, response) {
if (error) {
reject(error);
};
resolve(response);
});
}
}
You can do it like this where you add a .then() handler to your first promise that gets the place and then when that's available returns the object you want. The resolved results of your Promise.all() will then be the array of objects you want:
function getData(data, callback) {
let groupPromises = data.map(row => {
var coordinates = getCoordinates(row);
// add .then() handler here to convert the place result
// into the object you want it in
return getPlaces(coordinates).then(place => {
return {place: place, data: row};
});
});
return Promise.all(groupPromises)
.then(groups => callback(groups))
.catch(err => {
console.log(err);
throw err;
});
}
}
function getPlaces(coordinates) {
return new Promise(function(resolve, reject) {
if(coordinates == null) {
reject();
}
parameters = {
location: [coordinates.latitude, coordinates.longitude],
rankby: "distance",
};
googlePlaces.searchPlace(parameters, function (error, response) {
if (error) {
reject(error);
};
resolve(response);
});
}
}
FYI, since you're converting over to promises, why not just return the promise from getData() and not use a callback there at all? Your current code has no way of communicating back an error from getData() which is something that comes largely for free with promises.
In fact with pure promises, getData() could be simplified to this:
function getData(data, callback) {
return Promise.all(data.map(row => {
return getPlaces(getCoordinates(row)).then(function(place) {
return {place: place, data: row};
});
}));
}

Resources