Yeah, honestly the argument "async/await is better because I can write messy code using promises" is getting old. I can write really crappy code with any syntactical construct, but that doesn't make them any better or worse.
At the end of the day, I think it mostly comes down to style. If you prefer imperative code, you'll like async/await better because it's more imperative. If you prefer functional code, you'll like promises better.
I am Software Developer, currently interested in static type languages (TypeScript, Elm, ReScript) mostly in the frontend land, but working actively in Python also. I am available for mentoring.
First of all async await is a syntax sugar for Promises. Doing one vs another has not sense, both are in the same bandwagon. Secondly async/await can be more compared with Haskell do notation. Imperative code is about side effects, mutations. Until you don't do that you cannot say it's imperative code, therefore using async await vs raw promise is more code style
First of all async await is a syntax sugar for Promises. Doing one vs another has not sense, both are in the same bandwagon.
That doesn't make them the exact same, though. Nor does it make them equivalent in all regards. Even if they are meant to achieve the same goal, they are expressed differently. This means that there's got to be some difference between them. So it makes sense to discuss their differences.
Secondly async/await can be more compared with Haskell do notation.
And Structs in Elixir can be compared to classes. That doesn't make them Object-Oriented.
Imperative code is about side effects, mutations. Until you don't do that you cannot say it's imperative code
Aren't most asynchronous operations side effects? Last time I checked I/O operations were considered side effects, for instance.
There's more to it than simply saying "imperative code is about side effects and mutations". As far as I'm aware, all programming languages deal with side effects in one way or another, however functional they are.
Besides, imperative code also uses, for instance, statements. In order to deal with errors with async/await, you use a try/catch statement. If you want the value of a variable to depend on whether an asynchronous operation is successful, you need to create a variable outside of the try/catch statement and then mutate it depending on the result. I'm no expert, but this doesn't sound very functional to me.
therefore using async await vs raw promise is more code style
I'm pretty sure that was my comment's point as well ;-)
I am Software Developer, currently interested in static type languages (TypeScript, Elm, ReScript) mostly in the frontend land, but working actively in Python also. I am available for mentoring.
Aren't most asynchronous operations side effects? Last time I checked I/O operations were considered side effects, for instance.
Yes, but you have referred that async/await is imperative, and Promises are not. They both are imperative, as they are doing side-effects, so there is no difference.
There's more to it than simply saying "imperative code is about side effects and mutations".
This is the only definition of imperative programming which doesn't break at the long term. Imperative programming needs to change state. You can use statements and write purely functional code. Statement are for sure constructs made for potentially side-effectfull programs, but it doesn't mean you can't use them in FP.
Its look and feel sequential. Does it mean it is imperative code? Its truly not. Does it mean it is not functional code, nope it doesn't either. "Do notation" is syntax sugar for chaining monads, the same as async/await is syntax sugar for chaining Promises.
Async/await was firstly introduced in functional language - F#. There is nothing non-functional in the concept itself.
That is true that in JS when we use async-await the code uses likely statements and try/catch, and truly these aren't concepts from functional world, but there is no difference between .catch in Promise chain and try/catch in async/await. Its the same thing but written differently.
Although I understand the sentiment that Promise chaining feels more like declarative programming, in reality both ways change the state and not declare the change like IO Monad in Haskell does, therefore both are imperative.
I agree that in this case, there's no need for async/await, but whenenver you have logic that needs to happen between the async requests, it makes things so much cleaner.
E.g. I'm writing a Lambda that scrapes a website, then creates an Item to put into a DB, then makes the async db put:
module.exports.scraper=asyncevent=>{constresponse=awaitgot(URL);// pick the HTML elements I want, e.g. top 10 headlines// create the Item I want to put into db (10 headlines plus a date, e.g.)returnawaitclient.put(params).promise();}
Also agree with @leob
though that understanding Promises is still super. You may well need to combine the two as well, e.g.
constgetStuff=async()=>{constthingOnePromise=axios.get('thingOneAPI');constthingTwoPromise=axios.get('thingTwoAPI');const[thingOne,thingTwo]=awaitPromise.all([thingOnePromise,thingTwoPromise])console.log(thingOne+" and "+thingTwo);}
EU 🇪🇺 | Art, Tech & Good Vibrations 🤳 | Founder of ᴛᴏᴍᴏʀʀᴏᴡ 🌞 hellotomorrow.agency • Just started working on a new endeavour 👉 usepoe.app • Follow me on Twitter!
Location
Brussels, Belgium
Work
UX Engineer, Product Manager, sometimes Designer at Self
EU 🇪🇺 | Art, Tech & Good Vibrations 🤳 | Founder of ᴛᴏᴍᴏʀʀᴏᴡ 🌞 hellotomorrow.agency • Just started working on a new endeavour 👉 usepoe.app • Follow me on Twitter!
Location
Brussels, Belgium
Work
UX Engineer, Product Manager, sometimes Designer at Self
That syntax is a band-aid for the simplest problems. When you start trying to get conditionals or loops then you're fucked, and that happens very often in my universe.
Spot on, I was about to write exactly this as a comment ... if you write the code not in a "nested" way but in a "chained" way (and with only one catch block, not two) then the resulting code looks surprisingly similar to ... the async await style code!
The way the code was written in the article mimics more the old "callback hell" style with its deep nesting. The point of promises is exactly that you can get rid of that.
You can argue that async/await is still marginally easier to read than promises but the difference is minor.
Where async/await really gets simpler is if you have loops and conditions. But there you need to watch out - a loop with async calls is not the same as Promises.all(), there are situations where you still may want to use the latter!
In other words, aync/await is great but you should still understand Promises as well (which is the foundation that async/await is built on).
For further actions, you may consider blocking this person and/or reporting abuse
We're a place where coders share, stay up-to-date and grow their careers.
Wait, are you sure you know how to use promise?
This is totally same as your second example which writing in Promise
Obviously, nice and clean, Promise is better.
Yeah, honestly the argument "
async/await
is better because I can write messy code using promises" is getting old. I can write really crappy code with any syntactical construct, but that doesn't make them any better or worse.At the end of the day, I think it mostly comes down to style. If you prefer imperative code, you'll like
async/await
better because it's more imperative. If you prefer functional code, you'll like promises better.First of all async await is a syntax sugar for Promises. Doing one vs another has not sense, both are in the same bandwagon. Secondly async/await can be more compared with Haskell do notation. Imperative code is about side effects, mutations. Until you don't do that you cannot say it's imperative code, therefore using async await vs raw promise is more code style
That doesn't make them the exact same, though. Nor does it make them equivalent in all regards. Even if they are meant to achieve the same goal, they are expressed differently. This means that there's got to be some difference between them. So it makes sense to discuss their differences.
And Structs in Elixir can be compared to classes. That doesn't make them Object-Oriented.
Aren't most asynchronous operations side effects? Last time I checked I/O operations were considered side effects, for instance.
There's more to it than simply saying "imperative code is about side effects and mutations". As far as I'm aware, all programming languages deal with side effects in one way or another, however functional they are.
Besides, imperative code also uses, for instance, statements. In order to deal with errors with
async/await
, you use atry/catch
statement. If you want the value of a variable to depend on whether an asynchronous operation is successful, you need to create a variable outside of thetry/catch
statement and then mutate it depending on the result. I'm no expert, but this doesn't sound very functional to me.I'm pretty sure that was my comment's point as well ;-)
Yes, but you have referred that
async/await
is imperative, and Promises are not. They both are imperative, as they are doing side-effects, so there is no difference.This is the only definition of imperative programming which doesn't break at the long term. Imperative programming needs to change state. You can use statements and write purely functional code. Statement are for sure constructs made for potentially side-effectfull programs, but it doesn't mean you can't use them in FP.
This is example of do notation:
Its look and feel sequential. Does it mean it is imperative code? Its truly not. Does it mean it is not functional code, nope it doesn't either. "Do notation" is syntax sugar for chaining monads, the same as async/await is syntax sugar for chaining Promises.
Async/await was firstly introduced in functional language - F#. There is nothing non-functional in the concept itself.
That is true that in JS when we use async-await the code uses likely statements and try/catch, and truly these aren't concepts from functional world, but there is no difference between .catch in Promise chain and try/catch in async/await. Its the same thing but written differently.
Although I understand the sentiment that Promise chaining feels more like declarative programming, in reality both ways change the state and not declare the change like IO Monad in Haskell does, therefore both are imperative.
I agree that in this case, there's no need for async/await, but whenenver you have logic that needs to happen between the async requests, it makes things so much cleaner.
E.g. I'm writing a Lambda that scrapes a website, then creates an Item to put into a DB, then makes the async db put:
Also agree with @leob though that understanding Promises is still super. You may well need to combine the two as well, e.g.
(similar example given by Wes Bos in his talk on async/await which I highly recommend: youtube.com/watch?v=DwQJ_NPQWWo)
I'm not a async await hater, for me they are isomorphic which can transform to each other. I even like to mix using promise and async await.
The main problem of this article is the examples to judge async await is better than promise is pretty bad one.
Also, why is no one ever bothered by having to add that try/catch block... I don't understand. I hate it.
Yes,
catch
is much more elegant.Can you explain why there must be a try/catch block?
@Manuele J Sarfatti
In a classic promise you have:
If you switch to using await and you do:
but the promise fails (throws an exception), then you have yourself an unhandled exception, and the browser will most probably crash your app.
The equivalent of the classic promise is therefore:
PS: this is pseudo-code off the top of my head and most probably not working, it's just to give an idea
That syntax is a band-aid for the simplest problems. When you start trying to get conditionals or loops then you're fucked, and that happens very often in my universe.
Spot on, I was about to write exactly this as a comment ... if you write the code not in a "nested" way but in a "chained" way (and with only one catch block, not two) then the resulting code looks surprisingly similar to ... the async await style code!
The way the code was written in the article mimics more the old "callback hell" style with its deep nesting. The point of promises is exactly that you can get rid of that.
You can argue that async/await is still marginally easier to read than promises but the difference is minor.
Where async/await really gets simpler is if you have loops and conditions. But there you need to watch out - a loop with async calls is not the same as Promises.all(), there are situations where you still may want to use the latter!
In other words, aync/await is great but you should still understand Promises as well (which is the foundation that async/await is built on).