How to reject in async/await outside of catch statement? - javascript

As outlined by this SO post and answer, it is customary to throw an error from the catch statement that resides inside an async/await function like so:
} catch (error) {
throw new Error(400);
}
As highlighted by that same post, you typically wouldn't return a rejected promise (see below) since it's a semantic mis-match with 'try-catch' statements.
} catch (error) {
return Promise.reject(new Error(400));
}
By that same logic, should I be returning rejected promises when returning errors outside of catch statements from my async/await function instead of throwing them?
In other words is the following semantically inconsistent with the above logic?
async function promise () {
throw new Error('Some error');
}
And, is this the preferred way of returning an error inside an async/await function since async/await functions implicitly return a promise?
async function promise () {
return Promise.reject(new Error(400));
}
I'm aware both of the above snippets allow errors to be caught when consuming the promise.

You generally use throw where you can, i.e. in async functions or then callbacks, because it is simpler and therefore easier to read. return Promise.reject(…) does work but is lengthy.

Related

Remove indentations in a tree of promises

I want to remove indentations in a javascript funtion that inside has a variable that recive the value of a promise. Inside of it has a try-catch with some code and inside the try section has a fetch with his own then and catch.
My question is, how can I simplify the code, even creating new functions if needed, to reduce the amount of indentations.
Thanks for advance.
Here an example code:
function getData(url) {
const myVariable = new Promise((resolve, reject) => {
try {
fetch(url)
.then((resp) => resp.json())
.then(json) => {
//some code here
});
// more code here
resolve();
})
.catch(() => { // this catch is of the fetch
// more code here
resolve();
});
} catch (error) {
// more code here
reject();
}
});
}
Y tried to transform the fetch using the ES6 async-await but I can not use an async funtion inside a promise
You don't need a new Promise. Once you have a promise -- like returned by fetch() -- you don't need another promise to tell you when the first one resolves. The same is true when you have a promise coming from then() calls: you don't need an extra promise for them. It is an antipattern to use the promise constructor callback just to create another promise (using some API).
Your example code has syntax issues (there are more closing braces than opening), so the .catch() method is not called on a promise. Your comment suggests you want to call it on the promise returned by fetch, but then it should be chained before the first then call. Each then() returns a new promise, and maybe you wanted to chain .catch() on the last .then(). In that case it will catch rejections of any of the previously chained promises, which means the outer try/catch block is not going to ever execute the catch block -- there is nothing remaining that can cause a run time error.
Another issue with the code (once its syntax errors are fixed) is that although myVariable will be assigned a promise:
That promise will resolve to undefined
The getData function will return a promise that will resolve to undefined
That is not very useful. You should resolve that promise with the data you got from the json() promise.
You can use async await like so:
async function getData(url) {
try {
const resp = await fetch(url);
} catch(err) {
console.log("fetch failed with following error", err);
throw err; // rethrow so caller's promise gets rejected
}
try {
const data = await resp.json();
} catch(err) {
console.log("json() failed with following error", err);
throw err; // rethrow so caller's promise gets rejected
}
return data;
}
As in this example the error handling is nothing more than just reporting on errors and then bubble the error upwards, it would make sense that the caller would take the responsibility to report on errors:
function getData(url) {
fetch(url).then(resp => resp.json());
}

Escape multiple nested functions in NodeJS

I have code in Javascript that looks like this:
function someFunction() {
// Code
somePromise().catch(err => {
console.log(err);
});
// Mode Code
}
I would like to escape both somePromise().catch and someFunction() in the event that somePromise() is rejected. I tried using return but that only allows me to escape somePromise().catch. Is there any function that would allow me to break out of nested loops?
You can do that by using async/await:
function async someFunction() {
// Code
try {
await somePromise();
} catch (err) {
console.log(err);
return; // aborts further execution
}
// More Code
}
See async function for details.
Async/await solves the problem but it's important to understand why it solves the problem.
Promises are a mechanism for storing continuations. Functions you pass to then and catch are stored within the promise and are executed when the promise is resolved.
To solve this without async/await, you would simply return the Promise and use then to execute any code that should execute when the Promise does not reject:
function someFunction() {
// Code
return somePromise()
.then(result => {
// More Code
})
.catch(err => {
console.log(err);
});
}
This is essentially what async/await de-sugars to. Async/await is syntactic sugar around a state machine that wires up these continuations for you.

How to handle error and use promises correctly

To begin with, I am taking a follow up from this question I posted few moments ago
Now, I thought I knew Aysnc and Promise but clearly I am missing something.
Referencing to the Tagged answer by estus,
Unless API supports promises, errors should be entirely handled in
async function. Function body should be wrapped with try..catch to
rule out unhandled rejections which may result in exceptions in future
Node versions
From which I was able to comprehend that whenever we are using aysnc function and we want to do error Handling we need to use try..catch and for normal Promises we could simple do resolve/reject or if it is already a promise then we can chain and do .then and .catch but for that I got following reply on comment
Yes, you can expect an error. async/await is just syntactic sugar for
raw promises. Any async function can be rewritten in plain ES6
I might be keeping this question broad but can someone please help me in explaining..
When do we need to use
.then and .catch
and when do we need to use
try..catch
Also, What does it mean by
Unless API supports promises
Async await code looks cleaner and easy to read. The Promises were created to solve the callback hell problem but chaining a lot of promises also confusing. So async wait is a syntactical sugar and you can use any one of the .then or async await.
If you are using simple promises syntax then you can use .then.then.then.catch() syntax.
if you are using async and await then you have to use try catch. All the await will go in try and the catch condition would go in single catch.
Both these can be used when API/function you are using returns a promise.
try...catch in async function is syntactic sugar for catch() in raw promise. If raw promises are used for some reason (legacy code) then catch() may be used. This shouldn't be a problem in Node, since recent versions support async..await.
Notice that try..catch catches both synchronous and asynchronous errors in async. This should be taken into account to not leave synchronous errors unhandled with plain promise.
If API doesn't support promises, you cannot expect that promise rejection that is returned from a function be handled by API, so you need to do this yourself.
// So this is how promises work (as you may already be familiar with)
function promiseFu() {
return new Promise((resolve, reject) => {
reject();
})
.catch(e => {
// The exception has been handled
console.error("Error begin in promiseFu()!")
throw e; // <- now this triggers the second exception
})
}
// Asynchronous functions are the functions that ALWAYS returns a promise
// therefore, this is also correct
async function asyncFu() {
return new Promise((resolve, reject) => {
reject();
})
.catch(e => {
// The exception has been handled
console.error("Error begin in promiseFu()!")
throw e; // <- now this triggers the second exception
})
.catch(e => {
// Here the second exception gets handled as well, and asyncFu does not throw any exception in the end
})
}
// Now the power of async await
async function asyncMainFu() {
// using await before an async function would make it wait for the function to complete asynchronously before moving on
await asyncFu()
// await would do the same with promises as well
// await promiseFu() // <- this is correct as well
// BUT now, if you see promiseFu() is throwing the second exception which is not yet handled,
// asyncMainFu() would throw the same exception as well. unless handled by a try..catch block
try {
await promiseFu()
} catch(e) {
// handling the exception thrown by promiseFu and not throwing any new exception
// is a good idea if you think caller of asyncMainFu() might not handle it.
}
}

How do you prevent throwing exceptions in functions that return promises?

Functions that return promises should not throw exceptions but instead reject the promise, but what's the best practice for ensuring that this will always be the case? For example, even if I have an extremely simple class method like this...
foo(x) {
return this.promiseReturningApi.someMethod('bar', x);
}
...exceptions could be thrown if this.promiseReturningApi is undefined or someMethod is not a function (unless it's called after the first function in a promise chain).
To ensure that an exception is never thrown, is it necessary to always use a try-catch block like this:
foo(x) {
try {
return this.promiseReturningApi.someMethod('bar', x);
} catch (e) {
return Promise.reject(e);
}
}
(Or use something like Promise.resolve().then(() => this.promiseReturningApi.someMethod('bar', x)))
for any function that will return a promise, or how else would one ensure that exceptions are not thrown?
At the risk of committing the `explicit promise constructor anti-pattern, this would work:
foo(x) {
return new Promise(resolve => {
resolve(this.promiseReturningApi.someMethod('bar', x));
});
}
In the absence of any error being thrown, this will return the promise yielded by promiseReturningAPi as is. If an uncaught error is thrown anywhere, be it in the this.promiseReturningApi.someMethod line for whatever reason, or possibly even further down inside the call chain (such as inside promiseReturningApi, depending on how it is written), then the promise returned by foo will be rejected for that error reason. This is due to the specification of how thrown errors inside the "executor" (the function passed to new Promise) are handled--namely, they result in a rejected promise.
However, you should think long and hard about whether you really want to turn what is in essence an error in program logic (for example, a missing someMethod) into a rejected promise. You may find it is a better structure for your program to let "real" errors be errors, and bubble up and be reported as errors are, and reserve rejected promises for failed asynchronous operations such as a network request failing.
Here's what I think is the best practise
/**in provider**/
foo(x) {
return this.api.method(x); //Promise
}
/**in component**/
this.provider.foo('cat')
.then((res) => { console.log(res) }) //resolved
.catch((err) => { console.log(err) }) //rejected
In the function that returns the promise you could use promise.catch(...) like mentioned here https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch instead of the try/catch wrapper. This would potentially allow you to just return this.promiseReturningApi.someMethod('bar', x);.

Not being able to use promise

I'm trying to use promises in node.
But, the then part is not being executed.
The first function returns a resolve() instance.
How can I fix this?
This is the code:
exports.refresh_access_token = function (environment_hash) {
...
Model.update(values, {where: where}).then(function () {
console.log('updated!');
resolve("Success!");
}).catch(function (err) {
console.log('error on update');
});
...
}
async.map(accounts, function (account) {
module.exports.refresh_access_token(account.environment_hash).then(function () {
console.log('async called back');
});
}
It's not 100% clear what you're asking, but there are several errors you can fix:
To let the caller know when an internal promise is done, you must return that promise. So, add return to returnModel.update(...)`
resolve() is not a globally available function so there's no point in trying to call it from within a .then() handler. In fact, that probably causes an exception to be thrown because resolve is not defined.
When you are inside a .then() handler, the original promise is already resolved. You don't need to resolve anything. To return a value as the resolved value of the parent promise, just return that value.
When you log from within a .catch() handler, if you want the host promise to stay rejected, you have to re-throw the error. Otherwise, the error becomes "handled" and the promise changes to resolved.
Then, in your second code block, it really does not make sense to mix the async library with promises. They are different approaches to managing asynchronous operations. Pick one scheme or the other - don't mix. If you already have a promise like you do, then you can just return that promise and let the caller use the promise. No need for the async library when you already have promises.
You can fix those like this:
exports.refresh_access_token = function (environment_hash) {
...
return Model.update(values, {where: where}).then(function () {
console.log('updated!');
return "Success!";
}).catch(function (err) {
console.log('error on update');
// after logging, make sure promise stays rejected
throw err;
});
...
}
You need to return your promise to be able to use then
return Model.update(...)

Categories