I'm trying to return from my node server with koa to my angular front end the result of an api call. Here's my controller which require a npm module which provides access to their api. Await should wait for the result and than return, am I wrong? I did something similar in a previous project but I was asking data from a db.
Why it is not working?
const color = require('colourlovers');
exports.getAllColors = async (ctx) => {
ctx.res.body = await color.get('/color/FFFFFF', { format: 'json' }, (err, data) => {
console.log(data);//<---here is logging the data
return data;
});
console.log(ctx.res.body);//<---here is undefined
ctx.status=200;
};
You can not await color.get because it uses callbacks instead of promises (well, you can await it, but it doesn't do what you'd expect). So to use await, you need to build the promise yourself:
ctx.res.body = await new Promise((resolve, reject) => {
color.get('/color/FFFFFF', { format: 'json' }, (err, data) => {
if(err) reject(err);
else resolve(data);
});
});
Now it'll wait for the promise to be resolved or rejected.
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 am in a asynchronous function, trying to return the data from a callback function:
async function getData(){
const client = new google.auth.JWT(
keys.client_email,
null,
keys.private_key,
['https://www.googleapis.com/auth/spreadsheets']
)
let returnData
const finalData = (data) => {
returnData = data
}
async function gsrun(client) {
const gsapi = google.sheets({version:'v4', auth: client})
const options = {
spreadsheetId: '1d3ZiP1I9jJ2ddlD1Hx2ylWn1VFD_5lYQ9Ps9e9gEqI',
range: 'Sheet1!A1:H5'
}
const data = await gsapi.spreadsheets.values.get(options)
return data.data.values
}
client.authorize( async (err, tokens)=> {
if(err) return console.log(err)
let data = await gsrun(client)
finalData(data)
})
return returnData
}
And in the console I get: Promise { undefined }. How should I await that promise to resolve or to await the data?
You are still trying to return before the data was assigned. You are not "waiting" until client.authorize has called the callback because you can't. You can only "return data from a callback" if the callback is called synchronously. But that's not the case here. It doesn't matter that you declared the callback as async, what matters is how/when the caller (i.e. client.authorize) calls the callback.
Wrap the client.authorize in a promise and await that in your getData function.
async function gsrun(client) {
const gsapi = google.sheets({
version: 'v4',
auth: client
})
const options = {
spreadsheetId: '1d3ZiP1I9jJ2ddlD1Hx2ylWn1VFD_5lYQ9Ps9e9gEqI',
range: 'Sheet1!A1:H5'
}
const data = await gsapi.spreadsheets.values.get(options)
return data.data.values
}
function authorize(client) {
return new Promise((resolve, reject) => {
client.authorize((err, tokens) => {
if (err) {
reject(err);
} else {
resolve(tokens);
}
});
});
}
async function getData() {
const client = new google.auth.JWT(
keys.client_email,
null,
keys.private_key, ['https://www.googleapis.com/auth/spreadsheets']
)
await authorize(client);
return await gsrun(client);
}
Here authorize will throw an error if the authentication failed and return the tokens if it is successful.
I wrote a post about callbacks and data. While it doesn't go into promises, maybe it can help your understanding of callbacks.
Your client.authorize is already awaiting gsrun() function to return a resolve (I am not sure how the rejection from gsrun() is handled but I suggest you use a .then() to handle resolve/reject if not implement a try,catch statement).
Another issue is that following code will still run despite you awaiting gsrun(client)
return returnData
because it is not inside the finalData() function. I suggest you only execute it is set.
Here's to show that returnData is returned before data is assigned to it
function returnPromise() {
return new Promise((resolve, reject) => {
setTimeout(()=>{
resolve('Success')
},2000)
// reject('err')
})
}
async function test(){
returnPromise().then(
resolve=>{console.log(resolve)},
reject=>{console.log(reject)}
)
}
test()
console.log('I COME HERE FIRST') // Executed first before promise is returned
Here's a simple example of how you could implement rejection handling(for reference only)
function gsrun() {
return new Promise((resolve, reject) => {
//resolve('Success')
reject('err')
})
}
async function authorizeCallback(){
gsrun().then(
resolve=>{finalData(resolve)},
reject=>{console.log(reject)} // do error handling
)
}
My Codes below;
I've a then-catch block. My responseArray is a global variable. i got response from functionName function; but i can't use result out of then block. How can i use then response out of block?
My Codes below;
I've a then-catch block. My responseArray is a global variable. i got response from functionName function; but i can't use result out of then block. How can i use then response out of block?
module.exports = {
foo1: function(param){
return new Promise((resolve,reject) => {
var result = //some code here
resolve(result);
});
},
foo2: function(param){
return new Promise((resolve,reject) => {
this.foo1('abc').then(function(res){
let response = {
'item':'ok',
'result':res.some_field
};
console.log(response); // its ok here.
responseArray.push(response); //its ok here too
}).catch(err =>{
console.log(err);
reject(err);
});
console.log(responseArray); //nothing in array here
resolve(responseArray);
});
}
};
First thing to remember is that promises are asynchronous. Promises are doing exactly what they say, you are essentially signing a contract (promise) that you will get your data (or error) but not synchronously, but at some time in the future when the computations have finished.
In order to access your responseArray you will need to resolve your foo2 promise (inside of .then) and continue the promise chain by calling it, i.e.
module.exports = {
foo1: function(param){
return new Promise((resolve,reject) => {
var result = //some code here
resolve(result);
});
},
foo2: function(param){
return new Promise((resolve,reject) => {
this.foo1('abc').then(function(res){
let response = {
'item':'ok',
'result':res.some_field
};
console.log(response); // its ok here.
responseArray.push(response); //its ok here too
resolve(responseArray) // resolve the promise inside of .then
}).catch(err =>{
console.log(err);
reject(err);
});
});
}
};
foo2('someValue').then(response => {
console.log(response) // this will be your array
})
Also, as a side note, ensure you are not falling into the trap of the promise constructor anti-pattern. This is where you unnecessarily turn synchronous code into asynchronous code just for the sake of using "promises"
For example, a valid use of a promise would be to convert a callback, like so:
const getFile = filename => {
return new Promise((resolve, reject) => {
fs.readFile(filename, 'utf8', (err, data) => {
if (err) reject(err)
resolve(data)
})
})
}
whereas this is unnecessary:
const printData = data => {
return new Promise((resolve, reject) => {
resolve(console.log(data))
})
}
vs
const printData = data => {
console.log(data)
}
Read more here: What is the explicit promise construction antipattern and how do I avoid it?
I have strung together a promise to complete three actions synchronously. First, inserting into the db and resolving the id of that insert. Second, editing my json object to contain that last inserted id from the db. And third, sending a post request using npm requests. This is all wrapped in an express endpoint.
However, the requests call doesnt seem to be posting to my API. I have checked, removed the promises dependencies (which is needed to get the last inserted id from the db), and successfully posted the data using the exact same request structure. This leads me to beleive that
there is something wrong with my promise. Can anybody help?
function db() {
return new Promise(function(resolve, reject) {
db.run(`INSERT INTO scan_requests(name, date) VALUES(?,?);`, [req.body.name,req.body.date], function(err) {
if (err) {
console.log(err)
}
let q = this.lastID
resolve(q)
})
})
}
db()
.then(function(q) {
let data = {
url: 'https://api/key/',
body: {
name: req.body.name,
scan_callback: `http://localhost:80/${q}`
},
json: true
}
return(data)
}).then(function(data) {
res.json(req.body)
request
.post(data)
.on('error', function(err) {
console.log(err)
})
.pipe(res)
})
To chain promises, the resolve callback (executed in then) needs to return another promise, so you can chain another then to the first promise.
Just like this:
function db() {
return new Promise(function (resolve, reject) {
const str = 'Message from first Promise'
resolve(str)
})
}
db()
.then(function (outputFromFirstPromise) {
return new Promise(function (resolve, reject) {
const somethingElse = ', and output from second promise'
const result = outputFromFirstPromise + somethingElse
resolve(result)
})
})
.then(function (outputFromSecondPromise) {
// do something with outputFromSecondPromise
})
In your case the promise in the middle is not needed at all though. Why would you use a promise, only to construct your object data if you have nothing async to handle? Just put everything in the callback of your first promise.:
db().then(function (q) {
let data = {
url: 'https://api/key/',
body: {
name: req.body.name,
scan_callback: `http://localhost:80/${q}`
},
json: true
}
res.json(req.body)
request
.post(data)
.on('error', function (err) {
console.log(err)
})
.pipe(res)
})
One thing puts me off with Promise is that it is difficult to grasp with resolve and reject. Also the need of wrapping for Promise is ugly. Unless you use it very often, I tend to forget how to use them over time. Besides, code with Promise is still messy and hard to read. Hence I don't really like using it at all - because it has not much different from the callback hell. So I thought with ES7 await, I can avoid using Promise and giving me some more faith in JavaScript, but it seems that it is not the case. For instance:
const getOne = async () => {
return Weather.findOne(options, function(err, weather) {
//
});
}
const getWeather = async () => {
const exist = await getOne();
if (exist == null) {
return new Promise(function(resolve, reject) {
// Use request library.
request(pullUrl, function (error, response, body) {
if (!error && response.statusCode == 200) {
// Resolve with the data.
resolve(body);
} else {
// Reject with the error.
reject(error);
}
});
});
}
}
const insertWeather = async () => {
try {
const data = await getWeather();
} catch (err) {
res.set('Content-Type', 'application/json');
return res.status(200).send('Error occurs: ' + err);
}
}
insertWeather();
request(pullUrl, function (error, response, body) {} is an AJAX call from request package for nodejs.
I have to wrap it with Promise - but not precede it with await. Ideally this is what I imagine:
return await request(pullUrl, function (error, response, body) {...}
But if I do that, I will get the request object in return, instead of the data return from the request package - at this line:
const data = await getWeather();
Any ideas or solutions to avoid using Promise in the case such as the one above?
You'll find bluebird and node.js now come with promisify to allow you to consume Node callbacks as promises when you need too. Alternatively, you can consider a functional reactive approach and use a library like RxJS which will handle promises, node callbacks and other data types into streams.
const promisify = require('utils').promisify // alternatively use bluebird
const request = require('request-promise');
const weatherFn = promisify(Weather.findOne);
const weatherOptions = {};
async function getWeatherIfDoesNotExist() {
try {
const records = await weatherFn(weatherOptions);
if (records === null) {
return await request('/pullUrl');
}
} catch(err) {
throw new Error('Could not get weather');
}
}
async function weatherController(req, res) {
try {
const data = await getWeatherIfDoesNotExist();
} catch (err) {
res.set('Content-Type', 'application/json');
return res.status(200).send('Error occurs: ' + err);
}
}
function altWeatherController(req, res) {
return getWeatherIfDoesNotExist()
.then((data) => { // do something })
.catch((err) => {
res.set('Content-Type', 'application/json');
return res.status(200).send('Error occurs: ' + err);
})
}
As mentionned in the documentation here, you will need to wrap request with interfaces wrappers like request-promise (or you can find alternatives interface in the documentation) in order to return a Promise from request.