Where am I going wrong using promises and async? - javascript

I have written a function in 'apiCalls.js' file and have the following function:
function getAllData() {
new Promise(function(resolve, reject) {
async.parallel([
function(callback) {
request('http://urlcall', function(error, response, body) {
if(!error && response.statusCode == 200) {
return callback(null, body);
}
return callback(error || new Error('Response non-200'));
});
},
function(callback) {
request('http://urlcall', function(error, response, body) {
if(!error && response.statusCode == 200) {
return callback(null, body);
}
return callback(error || new Error('Response non-200'));
});
},
],
function(err, results) {
if(err) {
console.log(err);
reject(err);
}
console.log(results);
resolve(results);
});
});
}
I am then calling this function in my app.js file:
apiCalls.getAllData().then(function(returned) {
console.log(returned);
res.render('home');
});
I am getting an error where the value returned in then is undefined:
TypeError: Cannot read property 'then' of undefined
I am not sure where I am going wrong. I have resolved the promise and then used that value in the then function. Am I missing something here? I am new to using promises and asynchronous programming so am I missing some understanding here of how it is supposed to work?

First off, you really don't want to mix promises with plain callbacks with the async library. You need to pick one model to work with (promises or callbacks) and program all your control flow in one model. So, if you're moving to promises (which most of the world is), then skip the async library entirely. In this particular case, Promise.all() serves your purpose for two parallel requests.
Then, look to promisify the lowest level asynchronous operations you have as that lets you use promises for all your control flow and error handling. In your case, that's the request library which already has a promisified version called request-promise. In addition, it already checks for a non-2xx status for you automatically (and rejects the promise) so you don't have to code that. So, it appears you could replace every you have with just this:
const rp = require('request-promise'); // promise version of the request library
function getAllData() {
return Promise.all([rp('http://urlcall1'), rp('http://urlcall2')]);
}
Then, you can use it with .then():
apiCalls.getAllData().then(returned => {
console.log(returned);
res.render('home', returned);
}).catch(err => {
console.log(err);
res.sendStatus(500);
});

Related

JavaScript: Using Async/Await in a Promise

On the way of learning the concepts of asynchronous JavaScript, I got struggled with the idea behind the situation when they can be chained. As an example consider the following situation: a webhook calls a cloud function and as a requirement there is set a time interval by which the cloud function should response to the webhook. In the cloud function is called an operation for fetching some data from a database, which can be short- or long-running task. For this reason we may want to return a promise to the webhook just to "register" a future activity and later provide results from it e.g.:
async function main () {
return new Promise ((resolve, reject) => {
try {
db.getSomeData().then(data=> {
resolve({ result: data});
});
} catch (err) {
reject({ error: err.message });
}
});
}
Another way is to use async/await instead of a promise for fetching the data, e.g.:
async function main () {
return new Promise (async (resolve, reject) => {
try {
const data = await db.getSomeData();
resolve({ result: data });
} catch (err) {
reject({ error: err.message });
}
});
}
(The code is a pseudo-code and therefore all checks on the returned types are not considered as important.)
Does the await block the code in the second example and prevent returning of the promise?
async functions always return a Promise. It is up to the function caller to determine how to handle it: either by chaining with then/catch or using await. In your example, there is no need to create and return a new Promise.
You could do something like this for example:
async function main () {
try {
const data = await db.getSomeData()
return {result: data}
} catch (err) {
return {error: err.message}
}
}
// On some other part of the code, you could handle this function
// in one of the following ways:
//
// 1.
// Chaining the Promise with `then/catch`.
main()
.then((result) => console.log(result)) // {result: data}
.catch((err) => console.log(err)) // {error: err.message}
// 2.
// Using await (provided we are working inside an asyn function)
try {
const result = await main()
console.log(result) // {result: data}
} catch (err) {
console.log(err) // {error: err.message}
}
Try to avoid combining both methods of handling asynchronous operations as a best practice.

Get request data from a promise (RIOT API)

I have a request made with "request" from NodeJs, and I want to get the data with a promise. All good because the console shows me the information that I am requested. The problem is when I call the promise function, and the console shows me this. How can I get the real value?
let leagueTier = (accId) => new Promise(async (resolve, reject) => {
request({
url: `https://${reg}.api.riotgames.com/lol/league/v4/entries/by-summoner/${accId}${key}`,
json: true
}, (error, response, body) => {
if (!error && response.statusCode === 200) {
resolve(body[0].tier.toLowerCase())
} else {
reject(Error('It broke'))
}
})
}).then(function(res) {
return res;
})
This is where I call the function
.attachFiles([`./images/${leagueTier(body.id)}.png`])
(node:5868) UnhandledPromiseRejectionWarning: Error: ENOENT: no such file or directory, stat 'D:\Dev\shen-bot\images[object Promise].png'
How can I access the string of the request I made? Maybe I shouldn't use promises?
The leagueTier return value will be a promise that eventually resolves or rejects into a value. You can't simply add the return value as part of a string. You can either use await or then to wait for the value to come through.
// asuming you are in async function context
.attachFiles([`./images/${await leagueTier(body.id)}.png`]);
// or
leagueTier(body.id).then(tier => {
.attachFiles([`./images/${tier}.png`]);
});
Note that your current code:
.then(function(res) {
return res;
})
Does absolutely nothing and can be omitted.

How to get promise.response to return an API’s response?

TLDR: my promise.response needed to be called within both the API call and the promise.
I am attempting to get a return value from an API call via a Promise for a simple Express.js server.
This seems to be a topic of a lot of questions, but I have yet to successfully adapt an implementation to this case. I've also tried:
placing the API call within resolve()
async/wait implementations (willing to revisit)
Here's the basic structure of the code in question. There's a comment above the section where the trouble probably is.
Promise
const externalModule = require('<route to module>');
let promise = new Promise(function(resolve,reject) {
// This is probably where the problem is
let returnValue = externalModule.apiCall(parameters);
resolve(returnValue);
});
promise.then(function(returnValue) {
console.log(returnValue);
});
External Module
module.exports = {
apiCall: function(parameters) {
apiCall(
parameters,
function(err, response) {
if (err) {
console.error(err);
return;
} else {
console.log("success");
return response
}
}
)
}
};
If the code were working properly, we'd see two strings. One from inside the API call ("success") and another from it's return value. Because undefined is appearing before "success," we know that the resolve function has fired before the function above it has returned.
Logs from the Shell
> undefined
> "success"
You aren't providing a way to use the response from the api call. Convert that toa promise and then use it.
module.exports = {
apiCall: function(parameters) {
return new Promise((res, rej) => {
apiCall(
parameters,
function(err, response) {
if (err) {
rej(err);
} else {
res(response);
}
}
)
});
}
};
Then use it like so
let promise = externalModule.apiCall(parameters);

Is it possible to return values from asynchronous functions in node.js?

I'm likely reinventing the wheel here, but I want to make a function that takes a filename and returns the base64 encoded string asynchronously.
I'm really only familiar with callbacks, but trying to understand promises as well. My initial callback function looks like this --
blob2Base64callback.js
module.exports = {
blob2base64 : function(file) {
fs.readFile(file, 'utf8', function(err, contents){
if (err) {
console.log('file not found');
return '';
} else {
var base64str = Buffer.from(contents).toString('base64');
console.log(base64str.length);
return base64str;
}
});
}, //..other functions
};
This callback doesn't work because I'm not actually returning something from the blob2base4 function and if I modify this to something like the following:
module.exports = {
blob2base64 : function(file) {
return fs.readFile(file, 'utf8', function(err, contents){
//same implementation as above, cut to improve readability
});
}
};
It returns undefined because it doesn't wait to be executed. As far as I know, there is no possible way to return something to blob2base64 using callbacks.
So I looked into promises and tried the following:
blob2Base64promise.js
blob2base64 : function(file) {
console.log('function called');
const getFile = new Promise(function(resolve, reject){
fs.readFile(file, 'utf8', function(err, contents){
if (err) {
console.log('file not found');
reject(err)
} else {
//console.log(contents);
resolve(contents);
}
});
}).then(contents =>{
var base64str = Buffer.from(contents).toString('base64');
return base64str;
}).catch(err => console.log(err));
}
Is there anyway I can return the promise to the function and extract the resolve portion to get base64str? Am I right in thinking, this behavior is only possible with promises, but not callbacks. Or is it not possible with either syntax?
Also, I thought callbacks and promises couldn't be used together, yet this promise is just a wrapper around a callback.
(Answering in reverse order)
Typically callbacks and Promises are not mixed, just because it's messy. They are possible to intertwine, if necessary. There are utilities to turn callbacks into Promises ("promisify"), and Promises are becoming much more common, especially with the async/await syntax of ES6.
For Promises, be sure to return the Promise itself. In your example, return getFile. What the Promise chain eventually returns you must await. That could be the async/await keywords in ES6. You're call could be:
async function() {
let result = await blob2base64('myFile.png')
}
Which is just a nicer syntax for knowing your are returning a Promise. You could also do it like this:
function () {
blob2base64('myFile.png')
.then( result => {
// use result here
})
// you could catch as well.
}
For callbacks, you need to also pass a callback to your function. That is what makes it asynchronous and where you give your results:
blob2base64 : function(file, callback) {
fs.readFile(file, 'utf8', function(err, contents){
if (err) {
console.log('file not found');
callback(err)
} else {
var base64str = Buffer.from(contents).toString('base64');
console.log(base64str.length);
callback(null, base64str)
}
});
And you would call it like: blob2base64( 'myFile.png', function (err,result) {
})

Best practice of implementing javascript promise

Hi guys I am pretty new to js and asynchronous programming. I use node.js and express to start learning js serverside and asynchronous programming. I have probleom to implement something like callback promise async. I had used callback but I think my code becomes so messy and hard to maintain. Now I try to implement promise in my code below. My question is: do the way I use promise there is a good practice? Cause I think There's no different comparing to callback hell if I implement "nested" promise like my code below. How is the best practice of using promise? Thank you
update_data_profil(req, res) {
var nama_unit_org = req.body.nama_unit_org;
var nama_ketua_unit_org = req.body.nama_ketua_unit_org;
var nip_nim = req.body.nip_nim;
var email = req.body.email;
var no_hp = req.body.no_hp;
var params;
var user;
if (helper.isExist(nama_unit_org) && helper.isExist(nama_ketua_unit_org) && helper.isExist(email)
&& helper.isExist(nip_nim) && helper.isExist(no_hp)) {
if (nip_nim !== req.user.nip_nim) {
params = {
nip_nim: nip_nim
}
user = new User_Model(params);
user.getDataProfilByNIPorNIM()
.then(function (result) {
if (result) {
req.flash('message_err', "NIP/NIM telah dipakai akun lain.");
res.redirect('/manajemen_profil');
}
else {
params = {
id_user: req.user.id_user,
nip_nim: nip_nim,
nama_ketua_unit_org: nama_ketua_unit_org,
nama_unit_org: nama_unit_org,
email: email,
no_hp: no_hp,
};
user = new User_Model(params);
user.editDataProfil()
.then(function () {
params = {
session_id: req.sessionID
};
user = new User_Model(params);
user.clearSession()
.then(function () {
req.flash('message_success', 'Edit data profil berhasil. Silahkan login untuk melanjutkan');
res.render('index/login',
{
message_success: req.flash('message_success')
});
}).catch(function (err) {
req.flash('message_err', "Internal server error");
res.redirect('/');
});
})
.catch(function (err) {
req.flash('message_err', "Internal server error.");
res.redirect('/');
});
}
}).catch(function (err) {
req.flash('message_err', "Internal server error.");
res.redirect('/');
})
}
else {
params = {
id_user: req.user.id_user,
nama_ketua_unit_org: nama_ketua_unit_org,
nama_unit_org: nama_unit_org,
email: email,
no_hp: no_hp
};
user = new User_Model(params);
user.editDataProfil()
.then(function () {
req.flash('message_success', "Berhasil update profil.");
res.redirect('/manajemen_profil');
})
.catch(function (err) {
req.flash('message_err', "Internal server error");
res.redirect('/manajemen_profil');
});
}
}
else {
req.flash('message_err', "Tidak boleh ada field yang kosong!");
res.redirect('/manajemen_profil');
}
}
One of the most beautiful advantages of Nodejs promises is to avoid the callback hell process. And with promises, if you are again nesting one inside the other then you are creating a promise hell ;) .
Below is one of the better approach to use promises.
Chaining:
// Promises example using 'then'
user.getDataProfilByNIPorNIM().then(function(user) {
...
return user.editDataProfil();
}).then(function(editDataProfilResults) {
....
return user.clearSession();
}).then(function(clearSessionResult) {
....
return
}).catch(function(err){
.....
process error
})
I have come across below link, which explain usage of promises. It might be helpful.
https://www.joezimjs.com/javascript/javascript-asynchronous-architectures-events-vs-promises/
For now best practice is to use async/await.
The word async before a function means it always returns a promise. If the code has return
in it, then JavaScript automatically wraps it into a
resolved promise with that value.
The keyword await makes JavaScript wait until that promise settles
and returns its result.
It makes code pretty and easy to handle.
It is quite simple to use, as you can see on following links.
Link 1.
Link 2.
Link 3
Example:
async function getData(url) {
let v;
try {
v = await downloadData(url);
} catch(e) {
v = await downloadFail(url);
}
return processAnother(v);
}
or you can use it like :
async FunctionFun( ) {
const groups = await this.variableGroupsService.find();
const groups2 = await this.pageMarkersService.find();
const groups3 = await this.funnelStepsService.findFunnelSteps()
return anyOtherFunction(groups, groups2, groups3);
}
I'd say best practice as of 2018 is to use async/await instead of using promises in this way.
This article from MDN gives some good examples of how they can be used.
To give a very simple example, a small part of your code using promises:
user.getDataProfilByNIPorNIM()
.then(function (result) {
if (result) {
req.flash('message_err', "NIP/NIM telah dipakai akun lain.");
...
});
could be rewritten as:
try {
const result = await user.getDataProfilByNIPorNIM();
} catch(e) {
// catch errors here.
}
To briefly quote the abovementioned article:
An async function can contain an await expression that pauses the execution of the async function and waits for the passed Promise's resolution, and then resumes the async function's execution and returns the resolved value.
This feature has become a fundamental part of how asynchronous development in Javascript is done in 2018, and I'd personally say it's a de-facto standard.

Categories

Resources