Attempting to convert two promise functions using async/await - javascript

This is the prompt I am given:
Fortune teller functions
You'll be using the following functions provided in the ./utils/fortune-teller.js file. This library is just a way for you to practice working with promises. While you can see the source code in the file, you do not need to understand it fully or make any changes to it.
welcome()
The welcome() function returns a promise that, when resolved, will return a short welcome string.
Example:
welcome().then((response) => {
console.log(response);
// "Provide me a question and I'll give you an answer..."
});
goodbye()
The goodbye() function returns a promise that, when resolved, will return a short goodbye string.
Example:
goodbye().then((response) => {
console.log(response);
// "Best of luck in the future..."
});
tell()
The tell() function takes a string and returns a promise that, when resolved, will return a random fortune.
Example:
tell("Will the weather be warm today?").then((response) => {
console.log(response);
// "Outlook good."
});
If no argument is provided, then the function will return a rejection that returns a short error message.
Example:
tell().catch((response) => {
console.log(response);
// "A question is required..."
});
Functions to complete
Update the getFortune() and fullSession() functions to use async and await as well as try and catch. Note that these functions require you to log statements with console.log() and should continue to do so.
Here is what I have tried:
const { welcome, goodbye, tell } = require("../utils/fortune-teller");
async function getFortune(question) {
tell(question).then(msg => {
await console.log(`Your question was: ${question}`);
await console.log(`Your fortune is: ${msg}`)})
.catch(err => await console.log('There was an error: A question is required...'));
}
async function fullSession(question) {
welcome().then(msg => await console.log(msg))
getFortune(question)
if (!question) {
return;
}
goodbye().then(msg => console.log(msg));
}
module.exports = { getFortune, fullSession };
The question also requires that you use "await" at least 4 times, and that you are not to use any .then or .catch statements. So I have also tried:
const { welcome, goodbye, tell } = require("../utils/fortune-teller");
async function getFortune(question) {
try{
let response = await tell(question)
await console.log(`Your question was: ${question}`);
await console.log(`Your fortune is: ${response}`);
} catch (error) {
await console.log(`There was an errror: ${error}`);
}
}
async function fullSession(question) {
try {
let welcom = welcome();
let fortune = getFortune(question);
let bye = goodbye();
let responses = await Promise.all([welcom, fortune, bye])
console.log(responses[0]);
console.log(responses[1]);
console.log(responses[2]);
} catch (error) {
console.log(`There was an error: ${error}`);
}
}
module.exports = { getFortune, fullSession };
I encounter more issues with the second way than I do with the first its just eliminating the .catch and .then statements that's tripping me up because it seems like no matter what adjustments I make it only makes it run worse. Any help would be appreciated. Thanks!
Inlcuded here is also the fortune-teller.js file if anyone is interested in it:
const responses = require("./responses.json");
function selectRandomFortune() {
const num = Math.random() * responses.length;
const index = Math.floor(num);
return responses[index];
}
function welcome() {
const message = "Provide me a question and I'll give you an answer...";
return Promise.resolve(message);
}
function goodbye() {
const message = "Best of luck in the future...";
return Promise.resolve(message);
}
function tell(question) {
if (!question) {
const message = "A question is required...";
return Promise.reject(message);
}
const fortune = selectRandomFortune();
return Promise.resolve(fortune);
}
module.exports = { welcome, goodbye, tell };

here you go, exactly 4 awaits where they actually need to be
const { welcome, goodbye, tell } = require("../utils/fortune-teller");
async function getFortune(question) {
try {
const fortune = await tell(question);
console.log(`Your question was: ${question}`);
console.log(`Your fortune is: ${fortune}`);
} catch (err) {
// tell rejects with "A question is required..." so just log that
console.log(err);
}
}
async function fullSession(question) {
try {
const msg = await welcome();
console.log(msg);
await getFortune(question);
const response = await goodbye()
console.log(response);
} catch (err) {
console.log(err);
}
}
module.exports = { getFortune, fullSession };
Alternative fullSession
async function fullSession(question) {
try {
console.log(await welcome());
await getFortune(question);
console.log(await goodbye());
} catch (err) {
console.log(err);
}
}

so i switched a couple things around, 'getFortune' it seems did require a try/catch but now the only spot where its hung up is on goodbye() the response comes back as undefined
const { welcome, goodbye, tell } = require("../utils/fortune-teller");
async function getFortune(question) {
try {
const msg = await tell(question);
console.log(`Your question was: ${question}`);
console.log(`Your fortune is: ${msg}`);
} catch (err) {
console.log('There was an error: A question is required...');
}
}
async function fullSession(question) {
try {
const msg = await welcome();
console.log(msg);
const fortune = await getFortune(question);
console.log(`Your fortune is: ${fortune}`);
const response = await goodbye();
console.log(response);
} catch (err) {
console.log(err);
}
}
module.exports = { getFortune, fullSession };

Related

Upgrade .then .catch to async await and try catch

I'm tryng to upgrade this code for a better maintenance, this code uploads two images to a server, i know it's possible to get rid of those .catch, by applying async await functions, and try catch blocks, but it's pretty confusing for me, any help will be apreciated.
this._uploadService.makeFileRequest(Global.url + "/upload-image1/" + response.product._id, [], this.filesToUpload1, 'image')
.then((result: Product) => {
this.filesToUpload1 = null;
this._uploadService.makeFileRequest(Global.url + "/upload-image/" + response.product._id, [], this.filesToUpload, 'image')
.then((result: Product) => {
this.filesToUpload = null;
setTimeout( () => this._router.navigate(['/detail', this.saveProduct._id]), 800 );
})
.catch(err => {
console.log(err);
this._router.navigate(['/detail', this.saveProduct._id]);
})
})
.catch(err => {
console.log(err);
this._router.navigate(['/detail', this.saveProduct._id]);
})
I suggest using a pen and paper to draw a block diagram for the logic involved, i.e. which api gets called first, with what kind of data, then which api comes afterwards; also include any logical conditionals through branching.
After that, you should attempt to write something like
const aggregateFunction = async() => {
try {
const someResponse = await callFirstApi(); // return response
await callSecondApi(someResponse); // use the response of the first api for the second api
if (someConditional) {
await callThirdApi(); // response not returned (i.e. when not required)
}
} catch (error) { // catch all errors from all await if they're not within another try-catch
console.log(error);
}
}
This pattern should eliminate all then and catch blocks. If you need more specific error handling for calling say a specific api, wrap function call inside another try-catch block, but everything should still be within the outer try-catch so that all errors will be caught regardless.
this._uploadService.makeFileRequest = function(){
return new Promise(resolve => {
// do logic of file request
resolve(true);
})
}
var waitForTime = function() {
return new Promise(resolve => {
setTimeout( () => {
this._router.navigate(['/detail', this.saveProduct._id]),
resolve(true)
}, 800 );
})
}
var f = async function(){
try {
await this._uploadService.makeFileRequest(Global.url + "/upload-image1/" + response.product._id, [], this.filesToUpload1, 'image');
await this.fileToUpload1 = null;
await this._uploadService.makeFileRequest(Global.url + "/upload-image/" + response.product._id, [], this.filesToUpload, 'image')
await this.fileToUpload = null;
await waitForTime();
}
catch(e) {
// error logic
}
}
if (this.filesToUpload1 && this.filesToUpload) {
f()
}
this might be another cleaner approach with async,await and promise

Returning boolean from mongoose .exists function

I'm trying to learn some node.js and mongoDB. I'm writing a demo login system to that end.
I have a function called by my main api to check in the mongoDB whether a refreshToken exists.
const checkRefreshTokenDB = (tokenPayload) => {
const decoded = jwt.decode(tokenPayload);
RefreshToken.exists(
{ tokenId: decoded.refresh.tokenId },
function (err, result) {
if (err) {
console.log(err);
} else {
console.log('Result: ' + result);
}
}
);
};
I can see the RefreshToken.exists is working find in the console.log. What I'm struggling with is making this function return a simple true/false to the caller. At the moment it seems to be returning a promise.
Any help would be very appreciated
Thanks
One way to resolve the issue is by using async/await.
const checkRefreshTokenDB = async (tokenPayload) => {
const decoded = jwt.decode(tokenPayload);
return await RefreshToken.exists({ tokenId: decoded.refresh.tokenId });
};
Now you can call this function as shown below from an async function (await is only valid in async function)
const status = await checkRefreshTokenDB(tokenPayload);
console.log(status)
If it really is returning a promise, then use async/await:
const checkRefreshTokenDB = (tokenPayload) => {
const decoded = jwt.decode(tokenPayload);
RefreshToken.exists(
{ tokenId: decoded.refresh.tokenId }
, async function (err, result) { console.log(await result); });
};

Javascript async function return then-catch promise?

Introduction
I am new in the world of javascript promises and I need to understand how they work correctly...
Until know I have been doing this in my code:
const handleRefresh = () => {
setIsRefreshing(true);
fetchUserData()
.then(async () => { <--------- Using then because I return a promise in fetchUserData
await fetchUserPosts(); <------- Using await here
setIsRefreshing(false);
}).catch(err => { <--------- This will catch the error I have thrown in the function fetchUserPosts or inside the then body
// TODO - Show error
setIsRefreshing(false);
console.log(err)
);
};
const fetchUserData = async () => { <------ async function
const { firebase } = props;
const userId = firebase.getCurrentUser().uid;
const documentRef = firebase.getDatabase().collection("users").doc(userId);
// Fetch all the user information
return documentRef <--------- Returning the promise here
.get()
.then((doc) => {
if (doc.exists) {
// Get all user data
const data = doc.data();
console.log(data);
setUserData(data);
}
})
.catch((err) => {
throw err; <----------- Throwing error
});
};
I don't know if I am doing anti patterns... But basically I need to know if this is a good way and if I am doing this correctly.
Questions
Do I have to declare the fetchUserData function as async to return a promise?
Can I use the async await in the then/catch body?
Can I do this?
const handleRefresh = async () => {
setIsRefreshing(true);
await fetchUserData()
.then(async () => { <--------- Using then because I return a promise in fetchUserData
await fetchUserPosts(); <------- Using await here
}).catch(err => { <--------- This will catch the error I have thrown in the function fetchUserPosts or inside the then body
// TODO - Show error
console.log(err)
);
setIsRefreshing(false);
};
I would really appreciate if someone guides me. Thanks.
the words async and await are only syntactic sugar for then and catch.
This:
fetchUserData()
.then(data => return data )
.catch(error => return error)
is equivalent to:
async function getUserData() {
const userData = await fetchUserData()
return userData
}
Here you are returning anything (success or error). If you want to treat the error here, just put a try/catch clause.
async function getUserData() {
try {
return await fetchUserData()
} catch (e) {
return e.message
}
}
Note that you can only use the await clause within an async function.
1.
Function can return Promise without being declared as async as long as you don't await inside it,
2.
You should not use async-await inside then, simply return a Promise and it'll be resolved in the following then,
3.
When using async-await syntax, Promises are awaited in a declarative way as demonstrated below:
const handleRefresh = async () => {
try
{
const a = await getA()
// pass the result to another Promise
const b = await getB(a)
const c = await getC(b)
} catch (error)
{
handleError(error)
}
};

Changing script from request to axios - log pending promise

I'd like some help please as I'm quite new in node.js and working with node packages.
I'm having the following script which makes a GET http request running on node using request which is deprecated now
const foo = (bar, callback) => {
const url = 'https://some.api.com?key=abc123';
request({url: url, json: true}, (error, response) => {
if (error) {
callback('Oops, there is an error!', undefined);
} else if(response.body.foobarArray.length === 0) {
callback('No data found', undefined);
} else {
callback(undefined, {
foobar1: response.body.foobar1,
foobar2: response.body.foobar2,
})
}
});
}
console.log(foo('Hello')); // this logs {foobar1: 'Hello', foobar2: 'World'}
I'm trying to rewrite it using axios instead, so this is my code
const foo = async (bar) => {
const url = 'https://some.api.com?key=abc123';
try {
const response = await axios.get(url);
if (response.body.foobarArray.length === 0) {
return 'No data found';
} else {
return {
foobar1: response.body.foobar1,
foobar2: response.body.foobar2,
};
}
} catch (error) {
return 'Ooops! Something went wrong :(';
}
};
console.log(foo('Hello')); // This logs `Promise { <pending> }`
I'm not sure what I'm doing wrong here as I'm not very familiar how promises work exactly, but how can I fix this?
const foo = async (bar) => {
const url = 'https://some.api.com?key=abc123';
try {
return await axios.get(url).then(response => {
return new Promise((resolve, reject) => {
if (response.body.foobarArray.length === 0) {
return reject('No data found');
} else {
return resolve({
foobar1: response.body.foobar1,
foobar2: response.body.foobar2,
});
}
})
}).catch(err => {
return Promise.reject(err);
});
} catch (error) {
// return 'Ooops! Something went wrong :(';
return Promise.reject(`an error occurred : ${error}`);
}
};
foo('hello').then(result => {
console.log(result);
}).catch(err => {
console.log(`error ! : ${err}`);
});
async functions returns a promise. async functions use an implicit Promise to return its result. Even if you don't return a promise explicitly async function makes sure that your code is passed through a promise
as you are using axios asynchronous , it's response is a promise which must be handled inside .then().catch() functions .
if no error occurs you can access the response inside your .then() , else you will have access to your error on .catch()
inside your .then() you can now do what you want with data , returning a new Promise , using resolve() for success and reject() for failure .
You have 2 options here:
Option 1
Any async function returns a Promise (behind the scenes) so:
foo('Hello').then(console.log).error(console.error);
Option 2
You need to await for the result of foo function but, at the moment, you can't use await out of function scope level. So:
async function main() {
try {
const result = await foo('Hello');
console.log(result);
} catch (err) {
console.error(err);
}
}
main();
In future Node.js releases, using await at global scope will be allowed.

Confusion around 'nested' try/catch statements in Javascript

Essentially I have an async function containing a try/catch that calls another async function also containing a try catch, and I'm getting a bit confused about how to properly implement what I'm doing. Some "pseudocode" showing my current implementation:
const main = async () => {
try {
const test = await secondFunc();
console.log(test);
} catch(err) {
console.log('Found an error!');
console.log(err);
}
const secondFunc = async () => {
try {
await performSomeRequestExample();
} catch(err) {
if (err.x === 'x') {
doSomething();
} else {
//********
throw err;
//********
}
}
So what I'm trying to do is get the throw(err) (surrounded by the asterisks) to be caught by the catch in main() which will also call the console.log('Found an error!'), but what currently happens is the error is thrown from secondFunc(), the catch in main() is never hit and I get an unhandled promise rejection.
Any guidance on what I'm doing wrong?
My advice is to minimize using try/catch unless absolutely necessary. With async functions (or any functions that return a Promise object) you can usually simplify things by not worrying about try/catch blocks unless you need to do something specific with certain errors. You can also use .catch rather than try/catch blocks to make things easier to read.
For example your code above could be written like this:
const main = async () => {
const test = await secondFunc().catch(err => {
console.log("Found an error from secondFunc!", err);
throw err; // if you want to send it along to main's caller
});
if (test) {
console.log("Test", test);
}
};
const secondFunc = () => {
return performSomeRequestExample().catch(err => {
if (err.x === "x") {
doSomething();
} else {
throw err;
}
});
};
const performSomeRequestExample = () => Promise.reject("bad");
main().then(
() => console.log("worked"),
err => console.log("failed from main", err)
);
In secondFunc we don't need to use async since we can just return the promise coming back from performSomeRequestExample and handle any failures in the .catch.
You should use
const secondFunc = async () => {
performSomeRequestExample().then(res =>{
console.log(res);
})
.catch(err => {
console.log(err);
}
)
Add a return before the await of performSomeRequestExample.
const secondFunc = async () => {
try {
return await performSomeRequestExample();
} catch (err) {
if (err.x === 'x') {
console.log('x');
} else {
throw err;
}
}
}
or you can also use .catch() after the awaited function.
Another solution can be like this
const main = async() => {
try {
const test = await secondFunc();
console.log(test);
} catch(err) {
console.log('Found an error!');
console.log(err);
}
}
const secondFunc = async () => {
//return await performSomeRequestExample(); //for success
return await performSomeRequestExample(2); //for error
}
const performSomeRequestExample = async(abc=1) => {
return new Promise(function(resolve,reject){
if(abc ==1){
setInterval(resolve("yes"),400);
}else{
setInterval(reject("opps"),400);
}
});
}
main();
Test this code at this link:
https://repl.it/repls/JoyfulSomberTelevision

Categories