I'm running NodeJS with pg-promise for accessing my PostgreSQL.
This is my test, which fails with undefined:
function a() {
pgPromise.one('SELECT 1')
.then(row => {
return row;
})
.catch(error => {
console.log(error);
});
}
console.log(a());
I asume it fails with undefined because it's running asyncronized.
I've tried to optimize with:
async function a() {
var output = null;
await pgPromise.one('SELECT 1')
.then(row => {
output = row;
})
.catch(error => {
console.log(error);
});
return output;
}
console.log(a());
But that simply gives me:
[2018-09-13 08:37:09.521] [LOG] Promise { <pending> }
You must await for the result, so that you don't get the promise but its result once it's solved:
console.log(await a());
But your code is way too complicated. Your a function makes no real sense.
Change
async function a() {
var output = null;
await pgPromise.one('SELECT 1')
.then(row => {
output = row;
})
.catch(error => {
console.log(error);
});
return output;
}
to
async function a() {
try {
return await pgPromise.one('SELECT 1')
} catch(error) {
console.log(error);
}
}
If you're getting a syntax error on the await, it probably means you're not in an async function. A typical case in node is when you're at the root. The simplest solution is to wrap it in an async function:
;(async function(){
console.log(await a());
})();
async functions return a Promise, so you need to await it or use .then() in order to get the result.
Remember that await can only be used inside an async function so you need to change the structure of your code.
I recommend you check the documentation and also more information asynchronous programming in Javascript.
Keeping your first code like that, it could be fixed like this (still is a bit weird in my opinion):
function a() {
return pgPromise.one('SELECT 1')
.then(row => {
return row;
})
.catch(error => {
console.log(error);
});
}
a().then(console.log);
If you want to go with async/await, this example could be good for learning purposes:
async function a() {
const row = await pgPromise.one('SELECT 1');
return row;
}
a().then(console.log).catch(console.error);
In this case the error handling is being done outside the function, in the caller side (it could be done inside through try/catch, it depends on the use case).
Related
I'm reading data from db with using await so I used Promise but the function seems to return nothing
async function read() {
return new Promise((resolve, reject) => {
const db = new DB();
db
.read()
.then(result => {
resolve(result);
}).catch(() => {
reject('db-error');
});
});
}
(async () => {
const data = await read();
console.log(data); // undefined
})();
How can I make read() return result?
You are making it more complicated than it has to be. If you are already using an API that returns a promise then there is no need to use the promise constructor yourself.
And declaring a function as async is only necessary if you are using await in it to deal with promises.
So either do:
function read() {
const db = new DB();
return db
.read()
.catch(() => {
return 'db-error';
});
}
Or
async function read() {
const db = new DB();
try {
return await db.read();
} catch(error) {
return 'db-error';
}
}
If you are still not getting the value you want then you are not using the database API correctly and you have to read its documentation to figure out how to get back the right data.
The awesome guys who write the MDN Web Docs say that the result of await will be undefined if the promise that is being waited on is rejected: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await#handling_rejected_promises
Check out the following scenario.
This is a simple function that returns a Promise:
function asyncFunc(waitTime) {
return new Promise((resolve, reject) => {
setTimeout(() => {
// say we prefer people who do things in 3 seconds or less
if (waitTime <= 3000) {
resolve('Promise resolved! You\'re fast! :)');
} else {
reject('Promise rejected! You\'re slow! :(');
}
}, waitTime);
});
}
Let's test the function using a method similar to yours:
async function testAsyncFunc(waitTime) {
try {
const result = await asyncFunc(waitTime);
console.log(result);
} catch(error) {
console.error(error.message);
}
}
testAsyncFunc(3000); // Returns `Promise resolved! You're fast! :)`, as expected
testAsyncFunc(3001); // Returns `undefined` instead of `Promise rejected! You're slow! :(`
But since we want the actual rejection error of the asynchronous operation instead of undefined, the solution is to chain catch to the await statement to catch any rejection errors immediately you call the asynchronous function and then throw the error so it can be caught by any catch error handler you may want to use, like so:
async function testAsyncFunc(waitTime) {
try {
const result = await asyncFunc(waitTime)
.catch(error => {
// throw the rejection error so it can be handled by the catch block below
throw new Error(error);
});
// if no errors
console.log(result);
} catch(error) {
console.error(error.message);
}
}
testAsyncFunc(3001); // Returns the expected result: `Promise rejected! You're slow! :(`
I want to use the async function to bring out a particular value from my database to my the function global so I can use it in other parts of my application.
async function dimension() {
const result = await Settings.find({_id : "5d7f77d620cf10054ded50bb"},{dimension:1}, (err, res) => {
if(err) throw new Error(err.message, null);
const holder = res[0].dimension;
return holder;
console.log(holder) /// this print the expected result, that i want to make global
});
return {
result
};
};
console.log(dimension())
but the console.log of the dimension() gives me this
Promise { <pending> }
instead of the same value that
console.log(holder)
gives me nothing.
The problem is you are printing the result of dimension() as soon as you call it, but since this function is async, it returns a promise that is not yet resolved.
You do not need to use async/await here. Settings.find() seems to return a Promise. You can just return directly this Promise and use .then() to do something once that promise is resolved.
Like this :
function dimension () {
return Settings.find({ _id: '5d7f77d620cf10054ded50bb' }, { dimension: 1 }, (err, res) => {
if (err) {
throw new Error(err.message, null);
}
return res[0].dimension;
});
}
dimension().then(result => {
//print the result of dimension()
console.log(result);
//if result is a number and you want to add it to other numbers
var newResult = result + 25 + 45
// the variable "newResult" is now equal to your result + 45 + 25
});
More info on Promises and async/await
You have to await for your result, like this:
const result = await dimension();
console.log(result);
In that case, you don't even to make the original function async, just write it like this:
function dimension() {
return Settings.find({_id : "5d7f77d620cf10054ded50bb"},{dimension:1}, (err, res) => {
if(err) throw new Error(err.message, null);
const holder = res[0].dimension;
return holder;
});
};
async function myGlobalFunc() {
const result = await dimension();
console.log(result);
}
The best way to have this globally available is to just put your function dimension in a file somewhere. Then where you need the value, you just require it and await its value. E.g.
// get-dimension.js
// ...const Settings = require... comes here
module.exports = function getDimension() {
return Settings.find({_id : "5d7f77d620cf10054ded50bb"},{dimension:1}, (err, res) => {
if(err) throw new Error(err.message, null);
const holder = res[0].dimension;
return holder;
});
}
// your other modules, e.g.
// my-service-handler.js
const getDimesion = require('./get-dimension');
async function myServiceHandler() {
const dimension = await getDimension();
// do stuff with dimension.
}
You're using async/await, but you're mixing it with callbacks, this is not desirable as it leads to confusion. It's not clear what you expect to happen in the callback, but return holder; likely doesn't do what you expect it to do, returning from a callback does not work the same way returning from a promise handler works. Your entire implementation should work with promises so that the async/await syntax reads more naturally (as it was intended).
async function dimension() {
// We're already awaiting the result, no need for a callback...
// If an error is thrown from Settings.find it is propagated to the caller,
// no need to catch and rethrow the error...
const res = await Settings.find({_id: "5d7f77d620cf10054ded50bb"}, {dimension: 1});
return {result: res[0].dimension};
}
(async () => {
try {
console.log(await dimension());
} catch (err) {
console.error(err);
}
})();
Use dimension().then() in your code then it will work fine.
async function globalDimension() {
const data = await Users.findOne({ phone: 8109522305 }).exec();
return data.name;
}
globalDimension().then(data => {
console.log(data);
});
I've this snippet of code with a promise.
function f (number) {
return new Promise((resolve, reject) => {
if (number === 42) {
resolve({ success : "bar" })
}
reject({ bar : "foo" })
})
}
f(42)
.then(success)
.catch(bar);
f(43)
.then(success)
.catch(bar);
function success(input) {
console.log(input)
}
function bar() {
console.log("marianna")
}
and the following it the attempt to convert a promise to async/await syntax:
async function f (number) {
if (number === 42) {
return { success : "bar" }
}
throw { bar : "foo" }
}
f(42)
.then(success)
.catch(bar);
f(43)
.then(success)
.catch(bar);
function success(input) {
console.log(input)
}
function bar() {
console.log("marianna")
}
The output given from both scripts is equal. I think convertion is correct but I still got difficulties to "read" async code.
Anyway, .. why await is not necessary? When does await is required?
await can improve code reading. It treats asynchronous function call looks like synchronous call.
In your example, let's say if I want to run f(43) after f(42) finish. For this case, I can do like this below
f(42)
.then(() => {
success();
return f(43);
})
.then(success)
.catch(bar);
comparing to await
async function f (number) {
if (number === 42) {
return { success : "bar" }
}
throw { bar : "foo" }
}
async function run() {
try {
const result42 = await f(42); // async function but called like sync function
success(result42);
const result43 = await f(43);
success(result43);
} catch(error) {
bar(error);
}
}
run();
function success(input) {
console.log(input)
}
function bar() {
console.log("marianna")
}
A Promise is an object that represents an eventual completion or failure of an asynchronous operation.
There is nothing asynchronous in your code, both versions of function f() return a Promise that is already resolved or rejected. However, this does not change the way async/await works.
Using async and await your code should look like this:
async function f (number) {
if (number === 42) {
return { success : "bar" }
}
throw { bar : "foo" }
}
try {
res = await f(42)
success(res)
} catch(err) {
bar(err);
}
try {
res = await f(43)
success(res)
} catch(err) {
bar(err);
}
function success(input) {
console.log(input)
}
function bar(err) {
console.log(`error: ${err}`)
}
Behind the scenes, both versions of the code run the same way. But usually the async/await version is easier to read because the code is laid out the same way as synchronous code, with await in front of the asynchronous operations.
I think conversion is correct but I still got difficulties to "read" async code.
I have 2 things I think about when deciding on async/await vs then/catch syntax:
Should it run on installations with NodeJS lower than version 7.6? If yes, we can only use Promise then/catch as async/await starts with v7.6 NodeJS 7.6 support for async/await.
Which version would read cleaner to the next person maintaining my code?.
I use async/await when I think a section of code would read cleaner as a sequence of procedures in a try/catch block.
async-await-test.js
main()
/* test body */
async function main() {
try {
const result = await pingMeAfterOneSecond(true)
console.log('RESOLVED with ', result)
} catch (e) {
console.log('REJECTED due to', e)
}
}
/* some function that will resolve or reject as requested after 1 second -- this is same as in then-catch-test.js */
function pingMeAfterOneSecond(willSucceed) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (willSucceed) {
resolve(true)
} else {
reject(false)
}
}, 1000)
})
}
I use then/catch when I think a section of code would be in danger of looking like a nested spaghetti of try/catch blocks.
then-catch-test.js
/* test body */
pingMeAfterOneSecond(true)
.then(result => console.log('RESOLVED with ', result))
.catch(e => console.log('REJECTED due to', e))
/* some function that will resolve or reject as requested after 1 second -- this is same as in try-catch-test.js */
function pingMeAfterOneSecond(willSucceed) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (willSucceed) {
resolve(true)
} else {
reject(false)
}
}, 1000)
})
}
Hope this helps you think through the choices. Cheers,
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));
To overcome callback hell in javascript, I'm trying to use async await from legacy code written in SQLServer procedure.
But I'm not sure my code might be write properly.
My first confusing point is when async function returns, should it return resolve() as boolean, or just return reject and handle with try-catch?
Here is my code snippets.
Please correct me to right direction.
apiRoutes.js
app.route('/api/dansok/cancelDansok')
.post(dansokCancelHandler.cancelDansok);
dansokCancelController.js
const sequelize = models.Sequelize;
const jwt = require('jsonwebtoken');
async function jwtAccessAuthCheck(accessToken) {
if (!accessToken) {
return Promise.reject('Empty access token');
}
jwt.verify(accessToken,"dipa",function(err){
if(err) {
return Promise.reject('TokenExpiredError.');
} else {
return Promise.resolve();
}
});
}
async function checkFeeHist(dansokSeqNo) {
let feeHist = await models.FeeHist.findOne({
where: { DansokSeqNo: dansokSeqNo}
});
return !!feeHist;
}
async function getNextDansokHistSerialNo(dansokSeqNo) {
....
}
async function getDansokFee(dansokSeqNo) {
....
}
async function doCancel(dansokSeqNo) {
try {
if (await !checkFeeHist(dansokSeqNo)) {
log.error("doCancel() invalid dansokSeqNo for cancel, ", dansokSeqNo);
return;
}
let nextDansokSerialNo = await getNextDansokHistSerialNo(dansokSeqNo);
await insertNewDansokHist(dansokSeqNo, nextDansokSerialNo);
await updateDansokHist(dansokSeqNo);
await updateVBankList(dansokSeqNo, danokFee.VBankSeqNo);
await getVBankList(dansokSeqNo);
} catch (e) {
log.error("doCancel() exception:", e);
}
}
exports.cancelDansok = function (req, res) {
res.setHeader("Content-Type", "application/json; charset=utf-8");
const dansokSeqNo = req.body.DANSOKSEQNO;
const discKindCode = req.body.HISTKIND;
const worker = req.body.PROCWORKER;
const workerIp = req.body.CREATEIP;
const accessToken = req.headers.accesstoken;
//check input parameter
if (!dansokSeqNo || !discKindCode || !worker || !workerIp) {
let e = {status:400, message:'params are empty.'};
return res.status(e.status).json(e);
}
try {
jwtAccessAuthCheck(accessToken)
.then(() => {
log.info("jwt success");
doCancel(dansokSeqNo).then(() => {
log.info("cancelDansok() finish");
res.status(200).json({ message: 'cancelDansok success.' });
});
});
} catch(e) {
return res.status(e.status).json(e);
}
};
You'll need to rewrite jwtAccessAuthCheck(accessToken) so that it keeps track of the outcome of its nested tasks. In the code you've written:
// Code that needs fixes!
async function jwtAccessAuthCheck(accessToken) {
// This part is fine. We are in the main async flow.
if (!accessToken) {
return Promise.reject('Empty access token');
}
// This needs to be rewritten, as the async function itself doesn't know anything about
// the outcome of `jwt.verify`...
jwt.verify(accessToken,"dipa",function(err){
if(err) {
// This is wrapped in a `function(err)` callback, so the return value is irrelevant
// to the async function itself
return Promise.reject('TokenExpiredError.');
} else {
// Same problem here.
return Promise.resolve();
}
});
// Since the main async scope didn't handle anything related to `jwt.verify`, the content
// below will print even before `jwt.verify()` completes! And the async call will be
// considered complete right away.
console.log('Completed before jwt.verify() outcome');
}
A better rewrite would be:
// Fixed code. The outcome of `jwt.verify` is explicitly delegated back to a new Promise's
// `resolve` and `reject` handlers, Promise which we await for.
async function jwtAccessAuthCheck(accessToken) {
await new Promise((resolve, reject) => {
if (!accessToken) {
reject('Empty access token');
return;
}
jwt.verify(accessToken,"dipa",function(err){
if(err) {
reject('TokenExpiredError.');
} else {
resolve();
}
});
});
// We won't consider this async call done until the Promise above completes.
console.log('Completed');
}
An alternate signature that would also work in this specific use case:
// Also works this way without the `async` type:
function jwtAccessAuthCheck(accessToken) {
return new Promise((resolve, reject) => {
...
});
}
Regarding your cancelDansok(req, res) middleware, since jwtAccessAuthCheck is guaranteed to return a Promise (you made it an async function), you'll also need to handle its returned Promise directly. No try / catch can handle the outcome of this asynchronous task.
exports.cancelDansok = function (req, res) {
...
jwtAccessAuthCheck(accessToken)
.then(() => {
log.info("jwt success");
return doCancel(dansokSeqNo);
})
.then(() => {
log.info("cancelDansok() finish");
res.status(200).json({ message: 'cancelDansok success.' });
})
.catch(e => {
res.status(e.status).json(e);
});
};
I strongly suggest reading a few Promise-related articles to get the hang of it. They're very handy and powerful, but also bring a little pain when mixed with other JS patterns (async callbacks, try / catch...).
https://www.promisejs.org/
Node.js util.promisify