I have used a async function to wait for the settlement of promise and store the result in a variable. But it is not storing incase the promise is rejected. It is stroing result when promise is resolve but not when promise is rejecte. Any help will be highly appreciated.
async function umar() {
let somevar = false;
let myPromise = new Promise((resolve, reject) => {
if (somevar === true) {
console.log('I am resolved');
resolve('resolved')
}
else {
console.log('I am rejected.')
reject('rejected')
}
})
let myprom = await myPromise
console.log(myprom)
return myprom
}
let a = umar()
a.then((value)=>{
console.log(value)
},()=>{console.log('I got an error.')})
I was expecting the await to store the value in variable in both cases(when promise is rejected and resolve) but it is not doing so incase promise is rejected.
This is how await works. When the promise is rejected, it throws and you have to catch the error locally with a try/catch if you want to see the error locally. Your assignment statement let myprom = await myPromise will not be executed when myPromise rejects.
Promise rejections have to be caught in a .catch(), with the second callback to .then(fn1, fn2) or, if using await with a try/catch around the await (or sometimes you let the rejection propagate out of the async function and the caller can then catch the rejection.
In your umar() function, when myPromise rejects, the function will throw at the point of await myPromise and the promise that the async parent function returned will then reject with the same error that myPromise rejected with (as the async function automatically catches the throw and turns it into a rejection or its promise). You can either wrap a try/catch around that await to catch the error or in your code example, you can catch the error where you call umar() which you are already doing. If you log the actual error there, you would see the error you expect:
let a = umar();
a.then((value) => {
console.log(value)
}, (err) => {
// log the error
console.log('I got an error.', err);
});
Related
I am trying to figure out how to make the following piece of code use await. Could someone give me an example of how it should look like and the logic behind it?
const makeReq = (options) =>{
let promise = new Promise((resolve,reject) => {
pm.sendRequest(options, (error, response) => {
console.log('response: ',response.json())
if(error){
console.log('error:',error);
}
if(!error){
resolve(response.json());
}
else{
reject(error);
}
});
});
return promise;
}
const asyncReq = async (options) =>{
return makeReq(options)
.then(res =>{
return res;
})
.catch(err => {
console.warn('errors ending req ',err);
})
}
let libraryExport = {
checkResponseBody,
asyncReq
};
return libraryExport;
}
Let’s start with the async keyword. It can be placed before a function, like this:
async function f() {
return 1;
}
The word async before a function means one simple thing: a function always returns a promise. Other values are wrapped in a resolved promise automatically.
For instance, this function returns a resolved promise with the result of 1; let’s test it:
async function f() {
return 1;
}
f().then(alert); // 1
We could explicitly return a promise, which would be the same:
async function f() {
return Promise.resolve(1);
}
f().then(alert); // 1
So, async ensures that the function returns a promise, and wraps non-promises in it. Simple enough, right? But not only that. There’s another keyword, await, that works only inside async functions, and it’s pretty cool.
AWAIT :
The keyword await makes JavaScript wait until that promise settles and returns its result.
Here’s an example with a promise that resolves in 1 second:
async function f() {
let promise = new Promise((resolve, reject) => {
setTimeout(() => resolve("done!"), 1000)
});
let result = await promise; // wait until the promise resolves (*)
alert(result); // "done!"
}
f();
ERROR HANDLING :
If a promise resolves normally, then await promise returns the result. But in the case of a rejection, it throws the error, just as if there were a throw statement at that line.
async function f() {
await Promise.reject(new Error("Whoops!"));
}
CONCLUSION
The async keyword before a function has two effects:
Makes it always return a promise.
Allows await to be used in it.
The await keyword before a promise makes JavaScript wait until that promise settles, and then:
If it’s an error, the exception is generated — same as if throw error were called at that very place.
Otherwise, it returns the result.
Together they provide a great framework to write asynchronous code that is easy to both read and write.
With async/await we rarely need to write Promise.then/catch, but we still shouldn’t forget that they are based on promises, because sometimes (e.g. in the outermost scope) we have to use these methods. Also Promise.all is nice when we are waiting for many tasks simultaneously.
MERN noob here. Trying to learn Async/Await by simulating a busy server where client browser only get the update > 3 seconds later (i will manually refresh localhost:3000, after 3 seconds. I only need help on Node.js/ server side for this question)
Could you help rectify codes below? Kindly avoid proposing other ways/methods but show me how to achieve using below example. Thanks in advance.
const app = require('express')()
async function getData() {
//Purpose: to simulate a busy server that returns data back to browser, after 3 seconds delay
await setTimeout(() => {
return 'After waiting 3 seconds, return this sentense as the required data to the browser.'
}, 3000);
}
app.get('/', async (req, res) => {
try {
const data = await getData()
await res.status(200).send(`${data}`)
} catch (err) {
await res.status(400).send(`Unable to get data. Error message, "${err}"`)
}
})
app.listen(3000)
The problem here is that setTimeout doesn't return a promise so you can't use await with it. It just executes the given function after 3 seconds. You can get what you want by wrapping it in a Promise like this:
const app = require('express')()
function getData() {
//Purpose: to simulate a busy server that returns data back to browser, after 3 seconds delay
return new Promise((resolve) => {
setTimeout(() => {
resolve('After waiting 3 seconds, return this sentense as the required data to the browser.');
}, 3000);
});
}
app.get('/', async (req, res) => {
try {
const data = await getData()
await res.status(200).send(`${data}`)
} catch (err) {
await res.status(400).send(`Unable to get data. Error message, "${err}"`)
}
})
app.listen(3008)
Note that you need a return statement to return the promise inside of getData. You didn't have a return statement originally which means the function returns undefined (or if marked as async it gives a Promise that resolves to undefined).
Here we don't need to use async/await because you're not needing to use await until in the app.get. Using async/await in getData could be added but it would be redundant.
Realize that aync/await uses Promises - it's just an easy way to work with Promises. So you can't await on anything but a Promise. Note that async really just means "this function returns a Promise and we'll wrap any result in a Promise if it isn't already a Promise". So you cannot use async/await without having a Promise at some point.
But if you really want to use async/await for some reason maybe this example would help you:
async function getData() {
//Purpose: to simulate a busy server that returns data back to browser, after 3 seconds delay
const result = await new Promise((resolve) => {
setTimeout(() => {
resolve('After waiting 3 seconds, return this sentense as the required data to the browser.');
}, 3000);
});
console.log('We are done waiting 3 seconds');
return result; // <-- this returns a Promise that resolves to the result string
}
I want to get a value from a promise and then to return this value from the function. I'm using Axios to get the userId from the DB. I read that I should use .then but it still keeps returning a promise pending:
export async function getCurrentUserName(user){
const userName = await http.get(`${apiUrl}/users/me`,user)
.then(user =>{ return user.data.name });
return userName;
}
log:
userName Promise {pending}
_proto: Promise
[[PromiseState]]: "fulfilled"
[[PromiseResult]]: "avi"
The only way to get a value from a promise is with .then() or with await.
You cannot directly return the value from your function because your function returns BEFORE the asynchronous value is ready. So, your function needs to return the promise and the caller then must use .then() or await to retrieve the value from the promise.
In the code you show in your first code block, an async function ALWAYS returns a promise so you can't change that. Whatever value you return within the async function becomes the resolved value of the promise that was already returned.
To help you understand, let's review the timing of events in your function:
export async function getCurrentUserName(user){
const userName = await http.get(`${apiUrl}/users/me`,user)
.then(user =>{ return user.data.name });
return userName;
}
getCurrentUserName() gets called.
The function calls http.get()
The interpreter sees the await and suspends execution of the async function at the point and waits for the promise returned by http.get() to resolve/reject.
The function then returns an unresolved promise and execution in the code after the call to getCurrentUserName() continues. That calling code receives the unresolved promise. There is no way to return the value here because the value isn't yet known. That's why the promise is returned as it's a placeholder for the future value.
Sometime later, the http.get() resolves its promise and the execution of your function continues. It executes the .then() handler to get user.data.name.
The interpreter gets to the line return userName;. Since this is an async function that has already actually returned a promise, this return statement triggers that previously resolved promise to now get resolved with the resolved value set to userName.
A caller that was using await or .then() on the previously returned promise will get notified that the promise has now resolved and they will receive the userName resolved value.
This will solve your problem.
export async function getCurrentUserName(user) {
let userName = await http.get(`${apiUrl}/users/me`,user)
.then(user => {
if (user) {
username = user.data.name
} else {
alert('Failed to data')
}
return userName;
}
Or you can use a try and catch block.
async getCurrentUserName(user) {
try {
let response = await http.get(`${apiUrl}/users/me`,user);
let user = await response.json();
} catch(err) {
// catches errors both in fetch and response.json
alert(err);
}
}
Or So whenever you send data always use post rather than get
async getCurrentUserName(user) => {
await http.post(`${apiUrl}/users/me`,user)
.then(user =>{ return user.data.name })
.catch(function (error) {
return error;
})()
}
I've got an Api call that is converted to a promise. My handleError function inside the observable re-throws via throwError. This re-thrown error does not trigger any catch in the outer Promise chain.
callApi() {
return this.http.get(`${this.baseUrl}/someapi`)
.pipe(
map((data: any) => this.extractData(data)),
catchError(error => this.handleError(error))
).toPromise();
handleError(error) {
console.error(error);
return throwError(error || 'Server error');
}
Calling code...
this.someService.callApi()
.then((response) => {
// THIS GETS CALLED AFTER throwError
// do something cool with response
this.someVar = response;
})
.catch((error) => {
// WE NEVER GET TO HERE, even when I force my api to throw an error
console.log(`Custom error message here. error = ${error.message}`);
this.displayErrorGettingToken();
});
Why doesn't the throwError trigger the Promise catch?
You should not use toPromise() when possible.
Use subscribe instead of then.
Also when you catch the error in a pipe it won't be thrown in then because you already caught it, also when you throw the error in a catch error, it won't be emitted into the regular pipe flow of your response.
callApi() {
return this.http.get(`${this.baseUrl}/someapi`);
}
This is totally ok. Http.get() returns a singleton observable stream, which emits only ONE value and then completes. Subscribe to the Observable.
this.someService.callApi()
.subscribe((response) => {
// THIS GETS CALLED always wenn everything is ok
this.someVar = response;
},
(error:HttpErrorResponse) =>{
console.log(`Custom error message here. error ${error.message}`);
this.displayErrorGettingToken();
});
Observable is like an extended version of promise. Use it.
I'm trying to throw exception in the async code. If I throw it directly like this, it works fine. Example:
Query: {
requisitions: async (parent, args, { req }, info) => {
const user = await Auth.findOne({ _id: req.session.userId }).select('roles')
if (!user.roles.some(role => ['driver', 'requestant'].includes(role))) {
throw new ForbiddenError(ErrorCodes.UNAUTHENTICATED)
}
return true
}
}
But if I make a helper function to handle this, it doesn't work. I need the helper function because this roles check is needed at many places in the app.
Query: {
requisitions: async (parent, args, { req }, info) => {
hasRights(req, ['driver', 'requestant'])
return true
}
}
export const hasRights = async (req, allowedRoles) => {
const user = await Auth.findOne({ _id: req.session.userId }).select('roles')
if (!user.roles.some(role => allowedRoles.includes(role))) {
throw new ForbiddenError(ErrorCodes.UNAUTHENTICATED)
}
}
Note: the hasRights is exported from another file.
I have tried all combinations of try/catch blocks in both files but I just get the UnhandlePromiseRejectionWarning in the server console but the requisitons resolver continues in execution. I want it to stop if the exception is thrown. I have no idea why it only works one way and not the other, even though it is the same thing. Any help appreciated. Thanks.
Calling hasRights(req, ['driver', 'requestant']) can return a rejected promise, but you have no code to ever handle that. As such, it's an unhandled rejection.
When the throw is inline, it's caught by the async requsitions() function which then returns a rejected promise so the caller of requisitions() has a chance to catch it.
You can make sure a rejected promise returned from hasRights() is handled the same way by adding await in front of the hasRights() call like this:
Query: {
requisitions: async (parent, args, { req }, info) => {
await hasRights(req, ['driver', 'requestant'])
return true
}
}
This will allow the async requisitions() function to automatically catch a rejection from hasRights() the same way your original inline throw did.
You will, of course, have to make sure you handle rejected promises properly in the callers of requisitions().
It also occurs to me that you need to know that executing a throw inside an async function will be automatically caught by the async function and converted into a rejection of the promise that is returned by the async function. This is a feature of async functions.