Is async / await useless?

preview_player
Показать описание

🔗 Support the show by becoming a Patreon

🔗 Fun Fun Forum topic for the video

🔗 Async / Await video

🔗 Pair programming a messenger bot video

🔗 mpj on Twitter

🔗 Help translate the show to your language

I don’t actually believe that, but I would like to do a thought experiment where we test the hypothesis that all async / await code in JavaScript can be re-written just as well using promises, and that async / await doesn’t really add much value to JavaScript.

💛 Follow on Twitch and support by becoming a Subscriber
We record the show live Mondays 7 AM PT

💛 Fun Fun Forum

💛 mpj on Twitter

💛 CircleCI (Show sponsor)
Robust and sleek Docker-based Continuous Integration as a service. I used CircleCI prior to them becoming a sponsor and I love that their free tier is powerful enough for small personal projects, even if they are private. Use this link when you sign up to let them know you came from here:

💛 Quokka (Show sponsor)
Wonder how MPJ evaluates JavaScript inline his editor. Quokka is the answer - use this link when you buy to let them know you came from here:

💛 FUN FUN FUNCTION
Since 2015, Fun Fun Function (FFF) is one of the longest running weekly YouTube shows on programming 🏅 thanks to its consistency and quality reaching 200,000+ developers.

🤦‍♂️ The Failing Together concept is what makes FFF unique. Most coding content out there focus on step-by-step tutorials. We think tutorials are too far removed from what everyday development is like. Instead, FFF has created a completely new learning environment where we grow from failure, by solving problems while intensively interacting with a live audience.

Tutorials try to solve a problem. Failing Together makes you grow as a developer and coworker.

📹 Each show is recorded live on Twitch in a 2-hour livestream on Mondays. The host, assisted by the audience, is tasked to complete a programming challenge by an expert guest. Like in the real world, we often fail, and learn from it. This, of course, reflects what the audience identifies with, and is one of the most praised aspects of the show.

⏯ On Fridays, an edited version of the show is adapted for and published on YouTube.

Content Topics revolve around: JavaScript, Functional Programming, Software Architecture, Quality Processes, Developer Career and Health, Team Collaboration, Software Development, Project Management
Рекомендации по теме
Комментарии
Автор

Conciseness, readability & maintainability > Cleverness.

cryptochannels
Автор

Where I'm working on right now (and in most previous gigs actually) we are used among other things to write API tests which by nature are async: do this to the db, make a http request, check how the db changed after that request was completed successfully, etc. And we used to do that with either Promises or the "async" js library. When async await got into the lts version of node.js I took one of the test files and converted it, then looked at the diff. Not only was far fewer lines (I think it was a 2x reduction in total lines) but the identitation was kept to a minimum and the lines were easier to follow and read out loud.

victorb
Автор

This video can be renamed to "how to get things worse by using promises instead of async/await". 😂

hg.amaral
Автор

Replacing loops with recursion is exactly the sort of behaviour that async/await is trying to avoid - the transpiler emits this code so that you don't have to. Recursion is harder to reason about and you can introduce all sorts of fun performance issues. For example - how many arrays have you created there?

Long story short - you rewrote the async/await code with more characters, more calls and more conditions. Would you write for-loops with goto? 😉

AngusMcIntyre
Автор

First of all, big fan of your show, but you guys really struggled trying to argue that async await is useless in this episode and imho failed miserably ;-) From my experience simplicity and readability is always preferable over complexity especially in larger organizations where the skill may vary quite a lot among the developers. Developers being proud of being clever when performing such basic operations/tasks is usually a red flag.

Nobody in their right mind can say that the second (sql) sample is more readable and more straightforward after the refactoring. You guys literally made me laugh when you couldn’t motivate why the refactored code was better other than “I like it because it’s recursion, it’s neat because it’s recursion, it just feels *arghh*”, really?

The code became more complex after the refactoring and the argument that it makes you think harder to write that code comes up short imo. You said it yourself, “it’s hard for me to figure it out, but once I have it, it’s simple”. Honestly which code would you prefer to debug and find bugs in? Something you understands immediately and could write up without even thinking or something that feels so great because it’s recursion but you don’t understand it right away?

AjdenTowfeek
Автор

Some thoughts as I watch the video. Also, I'm a functional programming enthusiast, and use quite a lot of haskell in my free time, so there will be a lot of Haskell comparisons.
1- Is async await useless? I'm torn on this one. These days I mainly write Haskell in my free time, and async-await feels like an ad-hoc version of do-notation (much like promises feel like an ad-hoc version of a generic monad typeclass). So I wouldn't say it's useless, but the fact that they had to add an ad-hoc syntax for an ad-hoc construct kinda bothers me.
2- I think code with promises would be much clearer if "if" was an expression instead of a statement...
3- Couldn't you get rid of the nesting by just wrapping in a Promise[.resolve()], so you can call `then` after the outer `then`? (so it becomes
4- I don't agree with the "in your face" thing: personally I think that asynchronous flow should be as implicit as possible. For example, haskell's I/O is non-blocking, but while coding you don't really think about it. In my opinion, we should be able to program in a style that looks like synchronous code, but can be asynchronous, and it should be the language's job to transform between those representations. It's a lot like callback hell: it's pretty much Continuation Passing Style, and you can do it manually... but why do it when you can have a CPS-like Monad (like haskell's Cont") and write code that doesn't really look like CPS (albeit with the occasional callCC)?
5 - in the for loop example, i'd think you could so something like `users.map(user => await processUser(user.id))`, can't you?
6 - wait for each looks like a fold dying to come out. Maybe some sort of `compose(foldr(then), map(processFn)`? [where then(a, b) = a.then(b)
7- also, array destructuring feels like ad-hoc pattern matching :D although I guess it's not as ad-hoc, cause you can use it with objects too?
8- the stuff about error handling and aggregating data to me feels more of a consequence of the fact that Promises are very functional(as in functional programming) of a construct, and Javascript doesn't have very good support for functional programming, which means that there's quite a bit of stuff that you can't really do without it feeling weird or convoluted. It always feels like JS features are kinda thrown there, and don't really compose very well with each other.

But hey, that's just my 2c, feel free to disagree

TheMasterpikaReturn
Автор

I see folks juggling to avoid a flat out admision that async/await is better on long complex multi-step asynchronous programs. Mixing Promise and Promise All with a main driver script that uses async-await is a huge improvement to code readability. First learn callbacks, then write everything Promise / Promise All style and then graduate to writing the main body of your program in async/await style, this is really satisfying and super readable allowing anyone following in your footsteps to easily reason about your code, a clear sign that async-await carries less technical debt.

ErnestGWilsonII
Автор

I am not against promises and don't have any strong opinions to prefer one over the other but here is what I think about the things you said in the video:

The complexity of the code is not measured only by how nested it is, it is also measured by the number of things you need to keep in mind while reading the code itself.
13:32 you said you had to think about the code and after you figured it out it felt simple. For me, a sentence like this means the code smells.
I prefer the code to read like a well-written book and not like a smart poem. What I mean by that is that in well-written poems, you need to stop and think about every line and understand the meaning of it and how it contributes to the idea of the poem. In the book, on the other hand, you will read much more but the idea will be much more clear to you and you will get it faster.

Also for me, a code with promises looks a lot like a code with streams (like in RX for example), and it sometimes feels like reading a very long sentence with many ideas in it, you get lost in the middle and go back to re-read from start. I prefer reading short sentences one by one and breaking the ideas apart.

Probably you can refactor async/await code to promises in a good and understandable way, but it is harder to do so and there are much more ways to get it wrong.

ProgramArtist
Автор

6:37 "it is not to bad". Everything in one big line, lambda, with nested promise with a lambda with inline if, with another promise with another inline if. Definitely is not to bad, is insanely bad.

IF the main point of the away is to create better code, Yeh it works, but as everything else in programming if not used with sanity, it will end up with nightmare mess.

Even in functional programming breaking down those inline nested mess will make it more clean.
15:05, return a inline calls will never be "clean". As you said, "We return the query, than we process the user" ops, Return, end of function. So it is not so clean and have traps just "await"ing for unaware people. The actual order of the inline call can be trick. Specially if you throw some lambda with recursion.

if you write like you tried to say

query
get users
process

that is clean, And you return what ever is needed;

Sworn
Автор

Oh no, is MPJ saying you should write clever code again :(
Code styles are mostly a personal preference thing - if you are writing for yourself, go ahead and be clever. If you are wiring code that is to be shared - making it less clever and more clear is always better.

BrandonBey
Автор

You said something like this one on the burger code "This code is horrible and it has a very bad architecture". Given that it would not take much of your time to polish and refactor such code, I recommend you to always show a quality code for the sake of the followers who lack the coding quality.

Keep it up <3

matthewbarbara
Автор

I absolutely love that I scrolled down to see all the comments were about READABILITY. I'm only a junior programmer, so I can't say what senior programmers will find "easy to read" but recursion (as much fun as it is to write) is *horrible* for readability. And the main thing I hate about promises is that it keeps breaking up the scope so that I have to do weird tricks to pass data from the top to the bottom. Async/await solves those problems, at least when you don't need fine grained try/catch blocks. It's usually very easy to read and very easy to pass data where it needs to go. I love it.

LoveLearnShareGrow
Автор

of course it's useful. simple, clear and readable code!

emretekince
Автор

Here's a missed opportunity. Throw exceptions into the mix (pun intentional), and suddenly promise-based code look much better. Also, the example code has bad separation of concerns in general, and promise-based solution tend to push you towards solving those issues as well. Overall, async/await encourages some bad patterns if you look at it carefully.

hajimeyamasakivukelic
Автор

I like your video because it shows to me async/await is life❤️ even if you don't want to prove that

I understand what happens behind async / await and I think it is a great improvement to the lenguage because it helps you solve real tasks faster and helps you think at a higher level

I like that type of promises hell for educational purposes but not that much for real life anymore having async/await

nachovalera
Автор

One of the big reasons I much prefer the async/await version for getHamburger is this: imagine you're seeing this function for the first time, in the middle of a random codebase, no documentation, maybe the function isn't named as clearly... And you need to figure out exactly what the function returns. In the async/await example, I can scroll right down and see that it returns defaultBurger, or loadBurgers depending on the branching. In the case of promises, I have to sort of start following what's being returned at each level of indentation and slowly work my way to the end to see what's being returned. I could technically skip to the deepest level of indentation, but in that case I might miss some logic that happened before. This might take 2 seconds or 20 seconds longer, but the point is, it's time that you have to take to figure stuff out, as opposed to the async/await version which reads like a book. The more we can avoid these 2-20 second distractions, the less tired we will be 2, or 4, or 8 hours into the work day. And the more productive we will be as a result. So even if the code is only slightly more readable, to me that's a big win.

maagiapall
Автор

async / await is certainly an improvement. It doesn't require as much boilerplate as promises do (or callback style) and it makes the code easier to reason about, thus more maintainable.

As for the conclusion of this episode, that functional recursion is an alternative, do keep in mind that recursion is not "safe" in JS. Not all platforms support tail call optimization, hence with long lists (high depth), there's always a risk to run out of stack.

RazvanLaurus
Автор

This reminds me a little bit of the whole "assembly programming is better..." argument people used to have once high level languages started to appear.

Async / Await are simplifiers. USE THEM!

bloodaid
Автор

Where I used async/await the most, is with mongodb, when I need some arrays from differents collections (example: user, appointments, profesional and service) and if I had used promises, I would have had a "promise hell"

benbanda
Автор

The implementation of `waitForEach` isn't equivalent to the async/await example. In the async/await version the `processFunc` is only called for each item *after* the previous item has been processed. But the `waitForEach` version calls `processFunc` on every item in the list immediately.

This is because the recursive case is calling `waitForEach` eagerly instead of lazily. This can be fixed by wrapping the `then` in a function. e.g.
`processFunc(head).then(() => waitForEach(processFunc, tail))`.

Alternatively, a reduce can be used and the explicit recursion avoided entirely. e.g.
`const waitForEach = (processFunc, items) => items.reduce((acc, item) => acc.then(() => processFunc(item)), Promise.resolve());`

This has another advantage - it returns a promise that is resolved when all of the processing is complete!
(It also avoids people complaining about the potential stack overflow with recursion ;))

brenton
welcome to shbcf.ru