Is it's possible to rewrite next code with try-catch? I have heard that modern JS support it.
{
// GET /someUrl
this.$http.get('/someUrl').then(response => {
// get body data
this.someData = response.body;
}, response => {
// error callback
});
}
Yes, by try catch I assume you are referring to async/await introduced in ES6. It's worth bearing in mind that async/await only works on promise objects and performs exactly the same function but just provides you a more synchronous way to write your code that is (in most situations) easier to read.
Using async await the promise will resolve and return that value and then proceed to the next line of code, any exceptions can be handled in a catch block like so:
const someFunc = async () => {
try {
const response = await this.$http.get('/someUrl');
console.log(response);
} catch(err){
// Error handling
throw new Error(err);
}
}
While many may point you to async/await so you can use the actual try/catch keywords, I think it's more important to understand the code you have and make an informed decision. Most importantly, promises already handle the try/catch for you. Lets dive in.
In this code, you are dealing with promises.
goDoSomething().then(callThisFunctionWithResultsWhenDone);
One of my favorite properties of Promises are that they already handle
try/catch for you.
goDoSomething()
.then(doSomethingThatThrows)
.catch(doSomethingWithYourError)
.then(otherwiseKeepGoing)
Notice I used the .catch instead of passing an error handler in the same line. The inline error handler doesn't do what you may expect so I avoid it. Using .catch() allows you to intelligently handle asynchronous errors by short-circuiting a series of operations or handling errors from a series of steps individually without breaking out of the pipeline.
goDoSomething()
.then(throwError)
.then(thisIsSkipped)
.then(thisToo)
.catch(handleErrorButDontRethrow)
.then(doThisWithOrWithoutError)
.then(finishUp)
I always like to think of this style as a pipeline. Each catch statement catches any errors above it going up to the previous catch.
So, in your case:
$http.get(...)
.catch(handleRequestError)
.then(process)
.catch(handleProcessingError)
This would handle all possible errors but usually to handle the request error you actually would skip the processing step so then:
$http.get(...)
.then(process)
.catch(handleProcessingError)
Likewise, whatever calls this block may just want to skip the next block if the processing failed. Then you are left with:
$http.get(...)
.then(process)
If you find yourself re-throwing then maybe you should remove the catch and let it bubble.
IMO this is much more idiomatic JS code. The style introduced with async/await is a bit more familiar if you learned other languages first but it brings a very imperative feeling with it. In order to have the flexibility to handle each async operation individually your async/await code would need to look like this:
let intermediateStateStorage;
try {
intermediateStateStorage = await goDoSomething();
} catch {
handleThis();
}
try {
intermediateStateStorage = await process(intermediateStateStorage);
} catch {
handleThisOne();
}
This seems verbose compared to:
goDoSomething()
.catch(handleThis)
.then(process)
.catch(handleThisOne)
Neither are bad and I obviously have preference but I thought you'd like to know what you are dealing with so you can make an informed decision.
Related
I have been using ECMAScript 6 and ECMAScript 7 features already (thanks to Babel) in my applications - both mobile and web.
The first step obviously was to ECMAScript 6 levels. I learnt many async patterns, the promises (which are really promising), generators (not sure why the * symbol), etc.
Out of these, promises suited my purpose pretty well. And I have been using them in my applications quite a lot.
Here is an example/pseudocode of how I have implemented a basic promise-
var myPromise = new Promise(
function (resolve,reject) {
var x = MyDataStore(myObj);
resolve(x);
});
myPromise.then(
function (x) {
init(x);
});
As time passed, I came across ECMAScript 7 features, and one of them being ASYNC and AWAIT keywords/functions. These in conjunction do great wonders. I have started to replace some of my promises with async & await. They seem to add great value to programming style.
Again, here is a pseudocode of how my async, await function looks like-
async function myAsyncFunction (myObj) {
var x = new MyDataStore(myObj);
return await x.init();
}
var returnVal = await myAsyncFunction(obj);
Keeping the syntax errors (if any) aside, both of them do the exact same thing is what I feel. I have almost been able to replace most of my promises with async,awaits.
Why is async,await needed when promises do a similar job?
Does async,await solve a bigger problem? Or was it just a different solution to callback hell?
As I said earlier, I am able to use promises and async,await to solve the same problem. Is there anything specific that async await solved?
Additional notes:
I have been using async,awaits and promises in my React projects and Node.js modules extensively.
React especially have been an early bird and adopted a lot of ECMAScript 6 and ECMAScript 7 features.
Why is async,await needed when Promises does similar job? Does async,await solve a bigger problem?
async/await simply gives you a synchronous feel to asynchronous code. It's a very elegant form of syntactical sugar.
For simple queries and data manipulation, Promises can be simple, but if you run into scenarios where there's complex data manipulation and whatnot involved, it's easier to understand what's going on if the code simply looks as though it's synchronous (to put it another way, syntax in and of itself is a form of "incidental complexity" that async/await can get around).
If you're interested to know, you can use a library like co (alongside generators) to give the same sort of feel. Things like this have been developed to solve the problem that async/await ultimately solves (natively).
Async/Await provide a much nicer syntax in more complex scenarios. In particular, anything dealing with loops or certain other constructs like try/catch.
For example:
while (!value) {
const intermediate = await operation1();
value = await operation2(intermediate);
}
This example would be considerably more convoluted just using Promises.
Why is async,await needed when Promises does
similar job? Does async,await solve a bigger problem? or was it just a
different solution to callback hell? As I said earlier, I am able to
use Promises and Async,Await to solve the same problem. Is there
anything specific that Async Await solved?
The first things you have to understand that async/await syntax is just syntactic sugar which is meant to augment promises. In fact the return value of an async function is a promise. async/await syntax gives us the possibility of writing asynchronous in a synchronous manner. Here is an example:
Promise chaining:
function logFetch(url) {
return fetch(url)
.then(response => response.text())
.then(text => {
console.log(text);
}).catch(err => {
console.error('fetch failed', err);
});
}
Async function:
async function logFetch(url) {
try {
const response = await fetch(url);
console.log(await response.text());
}
catch (err) {
console.log('fetch failed', err);
}
}
In the above example the await waits for the promise (fetch(url)) to be either resolved or rejected. If the promise is resolved the value is stored in the response variable, and if the promise is rejected it would throw an error and thus enter the catch block.
We can already see that using async/await might be more readable than promise chaining. This is especially true when the amount of promises which we are using increases. Both Promise chaining and async/await solve the problem of callback hell and which method you choose is matter of personal preference.
Async/await can help make your code cleaner and more readable in cases where you need complicated control flow. It also produces more debug-friendly code. And makes it possible to handle both synchronous and asynchronous errors with just try/catch.
I recently wrote this post showing the advantages of async/await over promises in some common use cases with code examples: 6 Reasons Why JavaScript Async/Await Blows Promises Away (Tutorial)
await/async are often referred to as syntactic sugar to promises and let us wait for something (e.g. an API call), giving us the illusion that it is synchronous in an actual asynchronous code, which is a great benefit.
The things you want to achieve with async/await is possible with promises (but without the advantages of async/await). Lets take an example with this code:
const makeRequest = () => //promise way
getJSON()
.then(data => {
return data
})
makeRequest();
const makeRequest = async () => { //async await way
const data = await getJSON();
return data;
}
makeRequest()
Why is async/await prefered over promises?
Concise and clean - We don’t have to write .then and create an anonymous function to handle the response, or give a name data to a variable that we don’t need to use. We also avoided nesting our code. async/await is a lot cleaner.
Error handling - Async/await makes it finally possible to handle both synchronous and asynchronous errors with the same try/catch format.
Debugging - A really good advantage when using async/await is that it’s much easier to debug than promises for 2 reasons: 1) you can’t set breakpoints in arrow functions that return expressions (no body). 2) if you set a breakpoint inside a .then block and use debug shortcuts like step-over, the debugger will not move to the following .then because it only “steps” through synchronous code.
Error stacks - The error stack returned from the promises chain gives us no idea of where the error occurred and can be misleading. async/await gives us the error stack from async/await points to the function that contains the error which is a really big advantage.
My question consist of two parts:
Part 1
According to standard ES6 Promise I see that I forced to use catch block everywhere, but it looks like copy/paste and looks weird.
Example:
I have some class which makes request to backend (lets call it API class).
And I have a few requirements for API class using:
1) I need to make requests in different parts of my application with single request errors processing:
// somewhere...
api.getUser().then(... some logic ...);
// somewhere in another module and in another part of app...
api.getUser().then(... some another logic...);
2) I want so 'then' blocks would work ONLY when 'getUsers' succeeded.
3) I don't want to write catch block everywhere I use api.getUsers()
api.getUser()
// I don't want following
.catch(e => {
showAlert('request failed');
})
So I'm trying to implement single error processing inside of the class for all "users requests"
class API {
getUser() {
let promise = makeRequestToGetUser();
promise.catch(e => {
showAlert('request failed');
});
return promise;
}
}
...but if request fails I still forced to use catch block
api.getUser()
.then(... some logic...)
.catch(() => {}) // <- I forced to write it to avoid of “Uncaught (in promise)” warning
... otherwise I'll get “Uncaught (in promise)” warning in console. So I don't know the way of how to avoid of .catch block everywhere I use api instance.
Seems this comes from throwing error in such code:
// This cause "Uncaught error"
Promise.reject('some value').then(() => {});
May be you can say 'just return in your class "catched" promise'.
class API {
getUser() {
return makeRequestToGetUser().catch(e => {
showAlert('request failed');
return ...
});
}
}
...but this contradict to my #2 requirement.
See this demo: https://stackblitz.com/edit/promises-catch-block-question
So my 1st question is how to implement described logic without writing catch block everywhere I use api call?
Part 2
I checked if the same API class implementation with Q library will get the same result and was surprised because I don't get “Uncaught (in promise)” warning. BTW it is more expectable behavior than behavior of native ES6 Promises.
In this page https://promisesaplus.com/implementations I found that Q library is implementation of Promises/A+ spec. But why does it have different behavior?
Does es6 promise respects Promises/A+ spec?
Can anybody explain why these libraries has different behavior, which one is correct, and how implement mentioned logic in case if "ES6 Promises implementation" is correct?
I see that I forced to use catch block everywhere
No, you don't need to do that. Instead, return the promise created by then to the caller (and to that caller's caller, and...). Handle errors at the uppermost level available (for instance, the event handler that started the call sequence).
If that's still too many catchs for you, you can hook the unhandledrejection event and prevent its default:
window.addEventListener('unhandledrejection', event => {
event.preventDefault();
// You can use `event.reason` here for the rejection reason, and
// `event.promise` for the promise that was rejected
console.log(`Suppressed the rejection '${event.reason.message}'`);
});
Promise.reject(new Error("Something went wrong"));
The browser will trigger that event prior to reporting the unhandled rejection in the console.
Node.js supports this as well, on the process object:
process.on('unhandledRejection', error => {
// `error` is the rejection reason
});
Note that you get the reason directly rather than as a property of an event object.
So I don't know the way of how to avoid of .catch block everywhere I use api instance.
Surely the caller of getUser needs to know it failed? I mean, if the answer to that is really "no, they don't" then the event is the way to go, but really the code using api should look like this:
function useTheAPI() {
return getUser()
.then(user => {
// Do something with user
});
}
(or the async equivalent) so that the code calling useTheAPI knows that an error occurred; again, only the top-level needs to actually handle the error.
Can anybody explain why these libraries has different behavior, which one is correct, and how implement mentioned logic in case if "ES6 Promises implementation" is correct?
Both are correct. Reporting unhandled exceptions entirely in userland (where libraries live) is hard-to-impossible to do such that there aren't false positives. JavaScript engines can do it as part of their garbage collection (e.g.: if nothing has a reference to the promise anymore, and it was rejected, and nothing handled that rejection, issue the warning).
Is there any differences between async/await, and more standard promise notations using .then, .finally, and .catch
for example
functionThatReturnsPromise(someVar).then((returnedValueFromPromise) => {
console.log(returnedValueFromPromise)
})
vs
async functionThatReturnsPromise(someVar) {
await returnedValueFromPromise
}
I'm unsure if Promise chaining is just the old notation, and it's been replaced by the newer async/await. Is there still a use case for both? What is better practice?
You're misunderstanding how it works. With async/await you have a synchronous syntax flow of the code execution that's it:
try {
const returnedValueFromPromise = await functionThatReturnsPromise(someVar);
} catch (err) {
console.error(err);
throw err
}
Notice that
Code block must be inside an async scoped function
You still need to do err handling, can't assume promise will always work good
All values returned by async enclosed function are promises by default
It all depends on what you want. async/await are new. Think of it this way, they allow a promise to run like it was synchronous when it isn't.
Moreover using async/await makes your code cleaner and more readable.
And to answer your question, there are not much differences between them in terms of what they do. The syntax is just quite different.
Promise chaining is not old fashion, they are quite new, just that async/await came a bit later - giving you a "better" way of handling Promises.
Finally, you can use them interchangeably in your code.
Something to be careful with await, is that you'll need to wrap await statements in a try catch block in case the request fails which I personally think is uglier than regular promise chaining.
I'm coming from a PHP background and I'm trying to learn NodeJS.
I know that everything in Node is async but I've found that i've been using the async / await combo quite a lot in my code and I wanted to make sure I wasn't doing something stupid.
The reason for it is that I have a lot of situations where I need the result of something before continuing (for example for a small ajax request). This small ajax request has no other purpose other than to do the set of things that I want it to and in the order that I specify so even if I do things the "async way" and write it using a callback i'm still having to wait for things to finish in the right order.
Right now whenever I find myself in this situation I just use await to wait for the result:
ie:
var result = await this.doSomething(data);
Opposed to using a callback
this.doSomething(data, function(callback) {
// code
callback();
});
To me the first example looks cleaner than the second one which is why I've been opting for that. But I'm worried that I might be missing something fundamental here. But in a situation where there is nothing else to process below the async call and the only way for things to progress is for it to follow a syncronous style, is there anything wrong with using the first style over the second?
But I'm worried that I might be missing something fundamental here.
Nope, you're not, that's exactly what you want to do, assuming this.doSomething(data) is asynchronous (and if it's an ajax call, one hopes it is async) and that it returns a promise (which all functions defined with the async keyword do implicitly). (If it's not asynchronous, you don't need the await, although it's allowed.)
You're probably being a bit confused (understandably) by the fact that things are going through a transition. Until recently, the overwhelming convention in Node APIs (the built-in ones and ones provided by third-party modules) was to use the "Node callback" pattern, which is that a function that will do asynchronous work expects its last argument to be a callback, which it will call with a first argument indicating success/failure (null = success, anything else is an error object) with subsequent arguments providing the result. (Your second example assumes doSomething is one of these, instead of being a function that returns a promise.)
Example: fs.readFile, which you use like this:
fs.readFile("/some/file", "utf-8", function(err, data) {
if (err) {
// ...handle the fact an error occurred..
return;
}
// ...use the data...
});
This style quickly leads to callback hell, though, which is one of the reasons promises (aka "futures") were invented.
But a lot of Node APIs still use the old pattern.
If you need to use "Node callback"-pattern functions, you can use util.promisify to create promise-enabled versions of them. For instance, say you need to use fs.readFile, which uses the Node callback pattern. You can get a promise version like this:
const readFilePromise = util.promisify(fs.readFile);
...and then use it with async/await syntax (or use the promise directly via then):
const data = await readFilePromise("/some/file", "utf-8");
There's also an npm module called promisify that can provide a promise-ified version of an entire API. (There's probably more than one.)
Just because promises and async/await replace the old Node callback style in most cases doesn't mean callbacks don't still have a place: A Promise can only be settled once. They're for one-off things. So callbacks still have a place, such as with the on method of EventEmitters, like a readable stream:
fs.createReadStream("/some/file", "utf-8")
.on("data", chunk => {
// ...do something with the chunk of data...
})
.on("end", () => {
// ...do something with the fact the end of the stream was reached...
});
Since data will fire multiple times, it makes sense to use a callback for it; a promise wouldn't apply.
Also note that you can only use await in an async function. Consequently, you may find yourself getting into the habit of a "main" module structure that looks something like this:
// ...Setup (`require` calls, `import` once it's supported, etc.)...
(async () => {
// Code that can use `await `here...
})().catch(err => {
// Handle the fact an error/promise rejection occurred in the top level of your code
});
You can leave the catch off if you want your script to terminate on an unhandled error/rejection. (Node doesn't do that yet, but it will once unhandled rejection detection matures.)
Alternately, if you want to use a promise-enabled function in a non-async function, just use then and catch:
this.doSomething()
.then(result => {
// Use result
})
.catch(err => {
// Handle error
});
Note: async/await is directly supported in Node 7.x and above. Be sure your target production environment supports Node 7.x or above if your'e going to use async/await. If not, you could transpile your code using something like Babel and then use the transpiled result on the older version of Node.
Could you please help me to understand javascirpt async hell?
I think I am missing something important ☹ The thing is that js examples and most of the answers on the internet are related to just one part of code – a small snippet. But applications are much more complicated.
I am not going write it directly in JS since I am more interested of the design and how to write it PROPERLY.
Imagine these functions in my application:
InsertTestData();
SelectDataFromDB_1(‘USERS’);
SelectDataFromDB_2(‘USER_CARS’,’USERS’);
FillCollections(‘USER’,’USER_CARS’);
DoTheWork();
DeleteData();
I did not provide any description for the functions but I think it is obvious based on names. They need to go in THIS SPECIFIC ORDER. Imagine that I need to run a select into the db to get USERS and then I need run a select to get USER_CARS for these USERS. So it must be really in this order (consider the same for other functions). The thing is that need to call 6 times Node/Mysql which is async but I need results in specific order. So how can I PROPERLY make that happen?
This could work:
/* not valid code I want to present the idea and keep it short */
InsertTestData(
Mysql.query(select, data, function(err,success)
{
SelectDataFromDB_1(‘USERS’); -- in that asyn function I will call the next procedure
}
));
SelectDataFromDB_1 (
Mysql.query(select, data, function(err,success)
{
SelectDataFromDB_2(‘USERS’); -- in that asyn function I will call the next procedure
}
));
SelectDataFromDB_2 (
Mysql.query(select, data, function(err,success)
{
FillCollections (‘USERS’); -- in that asyn function I will call the next procedure
}
));
etc..
I can “easily” chain it but this looks as a mess. I mean really mess.
I can use some scheduler/timmers to schedule and testing if the previous procedure is done)
Both of them are mess.
So, what is the proper way to do this;
Thank you,
AZOR
If you're using a recent version of Node, you can use ES2017's async/await syntax to have synchronous-looking code that's really asynchronous.
First, you need a version of Mysql.query that returns a promise, which is easily done with util.promisify:
const util = require('util');
// ...
const query = util.promisify(Mysql.query);
Then, wrap your code in an async function and use await:
(async () => {
try {
await InsertTestData();
await SelectDataFromDB_1(‘USERS’);
await SelectDataFromDB_2(‘USER_CARS’,’USERS’);
await FillCollections(‘USER’,’USER_CARS’);
await DoTheWork();
await DeleteData();
} catch (e) {
// Handle the fact an error occurred...
}
})();
...where your functions are async functions, e.g.:
async InsertTestData() {
await query("INSERT INTO ...");
}
Note the try/catch in the async wrapper, it's essential to handle errors, because otherwise if an error occurs you'll get an unhandled rejection notice (and future versions of Node may well terminate the process). (Why "unhandled rejections"? Because async functions are syntactic sugar for promises; an async function returns a promise.) You can either do that with the try/catch shown, or alternate by using .catch on the result of calling it:
(async () => {
await InsertTestData();
// ...
})().catch(e => {
// Handle the fact an error occurred
});