I'm trying to do async NodeJS v8.10.0 and Express like so.
app.get('/settings', async function(req, res){
try {
const getTemperatureSettings = await getTemperatureSettings();
//...more await statements to be added.
res.render('settings', {
temperature_settings: getTemperatureSettings,
});
} catch (error) {
console.log('Error temperatureSettingRange', error);
}
});
function getTemperatureSettings() {
return new Promise(function (resolve, reject) {
couch.get(temperatureDb, "/_design/settings/_view/range?descending=true&limit=1").then(
function (data, headers, status) {
const temperatureSettingRange = data.data.rows[0].value;
resolve(temperatureSettingRange);
},
function (err) {
console.log('Could not get temperature settings', err);
}
);
});
}
However, I'm getting the following the error.
Error temperatureSettingRange ReferenceError: getTemperatureSettings is not defined
Even though getTemperatureSettings() is in the global scope, it seems it is out of scope --at least according to my syntax highlighter, it's not being called.
What is wrong here?
Related
Hi,
I have this code on my server file:
getName(){
const promise = new Promise((resolve, reject) => {
conn.query("SELECT name FROM members WHERE id=1", (err, res, fields) => {
if (err) reject(err);
resolve(res);
});
});
}
func() async {
try{
const data = await getName();
console.log(data);
} catch(e) {
console.log(e);
}
}
but I get this error: Unexpected token async so I removed async but then I get another error saying: Unexpected token {
What is happening here? I have node latest version: v10.24.1
Thank you.
The definition of your anonymous async function is wrong, try to change it like this example.
(async function() {
// Your code
})();
Also, you didn't return the promise from your getName() function.
getName() {
return new Promise((resolve, reject) => {
// Your code
})
}
More information about functions and async/await.
I think it is better if you use only async await and don't combine it with try and catch. That may give weird result. Try to refactor it only with async await syntax.
async func(){
const data = await getName();
console.log(data);
}
I'm fairly new to nodejs and have stumbled into a problem with my code.
The documentation for SQL Server and a guide I found on Youtube both handle their code this way, but after starting to use bycrypt I've noticed my function ends after the request is complete although I'm using .then().
Anyways, here's my code so far:
router.post('/login', (req, res) => {
getLoginDetails(req.body.username, req.body.password).then(result => {
console.log(result);
res.json(result);
})
});
async function getLoginDetails(username, password) {
await pool1Connect;
try {
const request = pool1.request();
request.input('username', sql.NVarChar, username);
request.query('SELECT * FROM users WHERE username = #username', (err, result) => {
if (err) {
return ({err: err})
}
if (result.recordset.length > 0) {
bcrypt.compare(password, result.recordset[0].user_password, (err, response) => {
if (response) {
console.log(result.recordset);
return(result.recordset);
} else {
return({message: "Wrong password or username!"})
}
})
return(result)
} else {
return({message: "user not found!"})
}
})
} catch (err) {
return err;
}
}
I tried logging both the request and the return value from the function getLoginDetails and the request log came faster, so I assume it's not waiting for the program to actually finish and I can't figure out why...
Sorry if that's obvious, but I'd love to get some help here!
EDIT:
router.post('/login', async (req, res) => {
// res.send(getLoginDetails(req.body.username, req.body.password))
await pool1Connect
try {
const request = pool1.request();
request.input('username', sql.NVarChar, req.body.username);
request.query('SELECT * FROM users WHERE username = #username', (err, result) => {
console.log(result);
bcrypt.compare(req.body.password, result.recordset[0].user_password, (err, response) => {
if (response) {
res.send(result);
} else {
res.send('wrong password')
}
})
//res.send(result)
})
} catch (err) {
res.send(err);
}
});
This code works, but when I tried to encapsulate it in a function it still didn't work.
#Anatoly mentioned .query not finishing in time which makes sense, but I thought mssql .query is an async function?
Your problem arises from an wrong assumption that callbacks and promises are alike, but on the contrary callbacks don't "respect" promise/async constructs
When the program hits the bottom of getLoginDetails the progrm execution has already split into 2 branches one branch returned you the (empty) result whereas the other one still busy with crypto operations.
Though it is true that an async function always returns a promise but that doesn't cover any future callbacks that might execute inside it. As soon as node reaches the end of function or any return statement the async function's promise get resolved(therefore future callbacks are meaningless), what you can do instead is handroll your own promise which encampasses the callbacks as well
router.post('/login', (req, res) => {
getLoginDetails(req.body.username, req.body.password))
.then((result)=>{
res.send(result);
})
.catch((err)=>{
res.send(err);
})
});
async function getLoginDetails(username, password) {
await pool1Connect
return new Promise( (resolve,reject) => {
try {
const request = pool1.request();
request.input('username', sql.NVarChar, username);
request.query('SELECT * FROM users WHERE username = #username', (err, result) => {
console.log(result);
bcrypt.compare(password, result.recordset[0].user_password, (err, response) => {
if (response) {
resolve(result);
} else {
resolve('wrong password')
}
})
})
} catch (err) {
reject(err);
}
});
}
You didn't return any result to getLoginDetails. Either you use async versions of request.query and bcrypt.compare (if any) or wrap request.query to new Promise((resolve, reject) like this:
const asyncResult = new Promise((resolve, reject) => {
request.query('SELECT ...
...
if (err) {
resolve({err: err}) // replace all return statements with resolve calls
}
...
})
const queryResult = await asyncResult;
I'm trying to read frpm a json file folder withing my program and i want to use a GET list endpoint to read through browser or postman, but i'm getting the above TypeError. Here is my code:
model.js:
const fs = require('fs');
function loadTeams() {
return new Promise((resolve, reject) => {
fs.readFile('./json/prov-nodes.json', (err, data) => {
if (err) reject(err);
const teams = JSON.parse(data);
console.log(teams);
resolve(teams);
});
});
}
app.use(bodyParser.json());
app.get('/list', (req, res) => {
let teams = [];
loadTeams()
.then(function(data){
teams = JSON.stringify(data);
console.log(teams);
**res.send(teams);** //intended to send to browser/postman response
console.log('try...part ..read call');
})
.catch(error => console.log(error))
res.send("My root page");
console.log(teams);
});
The loadTeams function does not return a promise, and therefore you cannot call .then().
You can wrap the function in a promise like this:
function loadTeams() {
return new Promise(function(resolve, reject) {
fs.readFile('./json/prov-nodes.json', (err, data) => {
if (err) reject(err);
try {
const teams = JSON.parse(data);
return resolve(teams);
} catch(e) {
reject(e);
}
});
});
}
In order to use loadTeams as an async function you should turn it into a function that returns Promise with a callback results:
function loadTeams() {
return new Promise((resolve, reject) => {
fs.readFile('./json/prov-nodes.json', (err, data) => {
if (err) reject(err);
const teams = JSON.parse(data);
console.log(teams);
resolve(teams);
});
});
}
The async function below is supposed to check if a url is a legit url
let CheckUrl = function (url, done) {
dns.lookup(url, function(err, address) {
if (err) return done(err);
done(null, true); //return true because I don't care what the address is, only that it works
});
}
The express.js code below gets the url but I'm having trouble understanding how to write the if statement so that it returns true or false.
// Gets URL
app.post("/api/shorturl/new", function(req, res) {
if (CheckUrl(req.body.url)) {
// do something
}
});
I'm not sure what to pass as the second argument in CheckUrl() in this if statement. Or maybe I wrote the first async function incorrectly to begin with?
Please use the async await
I have written a test code for you as below:
const express = require('express');
const app = express();
const dns = require('dns');
let CheckUrl = function (url, done) {
return new Promise((resolve, reject) => {
dns.lookup(url, function(err, address) {
console.log("err " , err)
if (err) {
resolve(false)
} else {
resolve(true)
}
});
});
}
app.post("/api/shorturl/new", async function(req, res) {
try {
let result = await CheckUrl(req.body.url);
console.log("result " , result)
res.send(result)
}
catch (error) {
console.log("in catch error " , error)
res.send(error)
}
});
app.listen(3000)
you can get the knowledge to know about the Promise here. The Promise object represents the eventual completion (or failure) of an asynchronous operation and its resulting value.
As mentioned by DeepKakkar, this was what I was looking for:
app.post("/api/shorturl/new", async (req, res) => {
try {
let result = await CheckUrl(req.body.url);
res.send(result)
}
catch (error) {
return new Error('Could not receive post');
}
});
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