[HN Gopher] I Avoid Async/Await
       ___________________________________________________________________
        
       I Avoid Async/Await
        
       Author : kiyanwang
       Score  : 149 points
       Date   : 2022-04-16 08:24 UTC (14 hours ago)
        
 (HTM) web link (uniqname.medium.com)
 (TXT) w3m dump (uniqname.medium.com)
        
       | moron4hire wrote:
       | I try to read every one of these sorts of articles that comes up.
       | I don't want to be caught flat-footed on some kind of weird
       | memory leak issue from not using a pattern correctly, or
       | something.
       | 
       | But every single one of these articles that I've read against
       | async/await has been nothing more than inventing "problems" to
       | try to convince people to stick to raw promises strictly because
       | that's what the author is comfortable with using. No actually
       | technical merits are discussed. Just fantasy issues so author can
       | feel superior for _not_ learning something new.
       | 
       | Like how the author claims you can't visually "see" that two
       | await calls can be parallelized. Speak for yourself, buddy. And
       | then complains about "having to go back to using promises" to
       | affect the parallelization. My dude, it was promises all along.
       | 
       | It's just syntax. Use it, don't use it, mix and match it. It's
       | not a moral issue.
        
         | gombosg wrote:
         | Yup, I agree that the author is missing the point here. You can
         | mix these syntaxes and have, say, "await Promise.all" without
         | guilt.
        
         | SideburnsOfDoom wrote:
         | > you can't visually "see" that two await calls can be
         | parallelized. Speak for yourself, buddy.
         | 
         | Agreed. My first thought was to try                 var
         | userSaveTask = save('userData', userData);       var
         | sessionSaveTask = save('session', sessionPrefences);
         | await Task.WhenAll(userSaveTask, sessionSaveTask);
         | 
         | I saw it before I got to the part of the text explaining how I
         | wasn't going to just see it.
         | 
         | > Furthermore, if we are to take advantage of parallelization
         | in the async/await example, we must use promises anyway.
         | 
         | Again, Speak for yourself, buddy. "await Task.WhenAll" does
         | that job in c#, and there must be a JavaScript equivalent.
         | 
         | IDK, this may be the c# mindset. yes, "async / await" is an
         | extra-ordinarily complex feature that can easily be done wrong.
         | But its also very useful and powerful, so lets not throw it
         | out.
        
           | chrisco255 wrote:
           | Yes, it is `await Promise.all()` in JS.
           | 
           | https://developer.mozilla.org/en-
           | US/docs/Web/JavaScript/Refe...
        
         | johnny22 wrote:
         | > Like how the author claims you can't visually "see" that two
         | await calls can be parallelized.
         | 
         | I'm not gonna pretend to be a JS expert here, but isn't that
         | exactly what you can see? Isn't that the whole point? It lets
         | you easily take a second look and decide to check if the
         | operations can happen in parallel or not.
         | 
         | I'm literally using 2 awaits in a row because android's BLE
         | implementation doesn't necessarily like more than 1 operation
         | happening at once, and I'm not doing enough other operations
         | such that I need to implement a whole queue to handle it.
         | 
         | (although maybe the library i'm using should implement that
         | queue)
        
       | __ryan__ wrote:
       | This article takes serious mental gymnastics to follow.
       | 
       | The main argument seems to be that an engineer with a working
       | mental model for basic promise chaining will be unable to
       | translate that to async/await, which is effectively syntax sugar
       | for the same thing.
       | 
       | The author says that multiple calls to _< promise>.then()_ is a
       | cue that the code is occurring serially, and the new keyword
       | _await <promise>_ somehow isn't.
       | 
       | There's a time and place for raw promises, but this article
       | hardly touches on anything actually wrong with async/await.
       | 
       | I've worked with engineers who actively fight against learning
       | their tools, like this. It's a nightmare. I don't trust them.
       | Don't be that person.
        
       | [deleted]
        
       | Aeolun wrote:
       | > It's because we are taught to read async/await code in a
       | synchronous mindset. We can't parallelize the save calls in that
       | first fully synchronous example, and that same -- but now
       | incorrect -- logic follows us to the second example.
       | 
       | What a weird idea. When I see a serial bunch of awaits the first
       | I think of is whether that makes any sense.
       | 
       | I think the author is kind of projecting his own views on
       | everyone else here.
        
       | lr4444lr wrote:
       | YOU may, buy your core frameworks may not. And if your
       | synchronous code is holding up async loops, you're gonna
       | potentially create a lot of very hard to diagnose problems.
       | Beware the foundation on which you build.
        
       | andix wrote:
       | I always do                 await Promise.all(...)
       | 
       | And now?
        
       | jrochkind1 wrote:
       | In that first example, `await` means exactly the same thing as
       | `then` for the purposes the author is talking about -- realizing
       | that something had been serialized that could have been done in
       | parallel.
       | 
       | I don't see why most engineers would be likely to recognize that
       | opportunity when written as `then` but not as `await`. If is is
       | true (and I'm not convinced it is), it seems like an education
       | problem rather than a reason to use promises rather than await.
       | It doesn't seem fundamentally harder to know that two `awaits` in
       | a row means serialization than to know that two `thens` in a row
       | does.
       | 
       | At least in that simple example where the use of `then` is
       | exactly parallel to the use of `await`. Perhaps it wasn't a good
       | example, and it really would be harder to reason about in a more
       | complicated example.
        
       | rwieruch wrote:
       | I always wondered why async/await introduced a concise way of
       | dealing with asynchronous code, but then breaks all this
       | conciseness with try/catch ...
       | 
       | Hence I tried to combine async/await with catch for an improved
       | readability [0] two years ago. Turns out I never used this
       | approach, because it's not common sense when working in a team
       | and still feels too verbose. Either one uses then/catch or
       | async/await with try/catch. However, I still feel try/catch still
       | makes code unattractive.
       | 
       | [0] https://www.robinwieruch.de/javascript-async-await-
       | without-t...
        
         | BigJono wrote:
         | I've never found this to be much of a problem in good code. API
         | failures in front-end code tend to fall into a couple of
         | buckets that can be abstracted away. If you want to preserve
         | the page and keep retrying with exponential backoff, you can
         | just implement that as a function that you then await until it
         | succeeds. If you can't recover and just want to show the user a
         | "shit's fucked, refresh the page" banner then you just need one
         | handler near the top of the stack and let the errors bubble up.
         | Most people are working in a declarative environment like React
         | where you can just have a hook wrapping your API calls that
         | exposes a potential error state to render accordingly.
         | 
         | You only really need to have try/catch blocks in 1 or 2 places
         | unless you have a lot of novel async stuff going on that needs
         | to recover from failures in specific ways. Most front-end code
         | shouldn't have a try/catch around every API call.
        
       | kareemsabri wrote:
       | The premise of this article seems flawed. We don't "code in a
       | synchronous mindset" when we use async/await. I would expect most
       | programmers are aware, after a 5 minute google search, that there
       | is an asynchronous process happening and we need to ensure no
       | execution after that line occurs until that process has resolved,
       | hence we use await. If you know what it is doing, it's not
       | complicated at all. It's identical to promise chaining but less
       | ugly.
        
         | daxfohl wrote:
         | Ultimately the problem of potentially missed opportunities for
         | parallelism there in regular sync code too. If we take the
         | author's point seriously, we should all be programming in a
         | language that requires explicit continuations everywhere just
         | to guard against accidentally serializing things.
        
       | pausmfib wrote:
       | I understand that the author is more familiar with the syntax of
       | promises. Nonetheless, having a syntax similar to synchronous
       | code allows developers to write more code remembering only the
       | couple of changes in syntax instead of having to memorise a
       | different one.
        
       | justsomeuser wrote:
       | I don't think of async await as "making async code act like sync
       | code".
       | 
       | I see it as adding meta data to a function type (async) and
       | allowing you to attach the result to a given function scope
       | (await).
       | 
       | The key utility of this is to allow you to use functions as a
       | unit of composition, allowing you to leverage their already built
       | tooling (IDE jump to function, stack frame based debugging, input
       | and output types (in:args -> out:return).
       | 
       | Messaging runtimes like Golang and Erlang use an additional
       | composition unit (channels and mailboxes), and do not allow you
       | to follow the "tree of functions" paradigm like async await does.
       | These result in having to follow a network graph of messages and
       | nodes to find out what will happen.
       | 
       | You need to understand you are dealing with an event loop before
       | you use async await. I think this is the issue the author is
       | raising.
        
       | phendrenad2 wrote:
       | Async/await was the latest buzzword a few years back, but it
       | never had any substance. A lot of inexperienced programmers
       | thought it was the greatest thing ever. Unfortunately, they were
       | overly focusing on the look of the code, and not the true
       | readability or usability of the code. Async/await certainly makes
       | you code "look" synchronous, but it's just shuffling the
       | complexity around. The complexity is still there, and you will
       | have to think about it.
        
       | stupidcar wrote:
       | > The keywords async and await should give us the same intuition
       | that the then does in the third. But I'll wager for many
       | engineers it doesn't.
       | 
       | It does.
        
       | AWebOfBrown wrote:
       | Agree that try/catch is verbose and not terribly ergonomic, but
       | my solution has been to treat errors as values rather than
       | exceptions, by default. It's much less painful to achieve this if
       | you use a library with an implementation of a Result type, which
       | I admit is a bit of a nuisance workaround, but worth it. I've
       | recently been using: https://github.com/swan-io/boxed.
       | 
       | By far the greatest benefit is being able to sanely implement a
       | type-safe API. To me, it is utter madness throwing custom
       | extensions of the Error class arbitrarily deep in the call-stack,
       | and then having a catch handler somewhere up the top hoping that
       | each error case is matched and correctly translated to the
       | intended http response (at least this seems to be a common
       | alternative).
        
       | eyelidlessness wrote:
       | Long rant is long, so I'll leave a tl;dr: regardless of how you
       | feel about the syntactic sugar aspect, async/await has a runtime
       | advantage of suspending the stack rather than exiting early,
       | which is (IMO) of greater benefit than the syntactic improvement.
       | 
       | - - -
       | 
       | I'm in the process of gradually moving several decade-old JS
       | projects from explicit Promise APIs to async/await. The reason
       | for this is _not_ the syntactic sugar (although that's quite a
       | benefit, and I disagree wholeheartedly with the article on that
       | point). The reason is that, at least with native Promises, the
       | actual runtime behavior of async /await is considerably better.
       | Because await suspends the stack, where .then/.catch enter a new
       | stack frame.
       | 
       | I do see this has been discussed some in another thread, but I
       | feel like it deserves more direct attention. It's true that you
       | can use libraries like Bluebird or whatever to get more accurate
       | stack traces. But this is done by tracking Promise chains in user
       | space. This is fine but it comes with a cost. Even if the library
       | is quite fast (as Bluebird is), you still incur the cost of
       | downloading and parsing it. Especially on HN where JS bloat is a
       | daily topic, I'd hope this can be appreciated.
       | 
       | In my case, this cost wouldn't be worth it even if the Promise
       | API were clearly better. These projects need to run efficiently
       | on low power mobile devices with limited connectivity. And we
       | need to be able to diagnose runtime errors to address outstanding
       | bugs. A library is a non-starter, and native Promise APIs
       | actively hinder progress. The behavior of async/await is clearly
       | superior.
       | 
       | Suspending the stack, either with async/await or generators,
       | affords significantly better debugging capabilities. It allows
       | Error stacks and console.trace to take better advantage of source
       | maps.
       | 
       | It's also a much better optimization target for browsers. This
       | isn't just academic: even if async/await is semantically
       | equivalent to Promise, it's not a guarantee that the underlying
       | .then/.catch will even be called if there's no explicit Promise
       | in the code. I've seen cases where they're not, which was
       | baffling until I understood (and this is how I came to
       | understand) the difference in runtime behavior.
        
       | steve_taylor wrote:
       | I'd like to see the author rewrite a for-of loop that contains
       | async code in the body as traditional promise code, then look me
       | in the eye and tell me the for-of version is more awkward.
        
       | adontz wrote:
       | I believe author misses one important point.
       | 
       | Async/await optimizes for throughput, not latency. Use case is
       | many lightweight tasks you want to parallel as wholes. Web APIs,
       | web sites are usual examples.
       | 
       | However, if you need other kind of optimizations, like two
       | parallel saves within one request, maybe async/await is not what
       | you need in the first place.
        
         | jrochkind1 wrote:
         | The performance characteristics of promises and async/await are
         | identical, no?
        
           | adontz wrote:
           | Yes, however capabilities are not the same. Promises are
           | lower level primitives.
        
           | zkldi wrote:
           | they are. async functions sre just syntactic sugar for
           | returning promises.
        
       | recursivedoubts wrote:
       | I work on a web scripting language that abstracts away
       | asyc/await:
       | 
       | https://hyperscript.org/docs/#async
       | 
       | we call it "Async Transparency"
       | 
       | It lets you write code like this:                 fetch /some-url
       | as json       put the result's content into me
       | 
       | where fetch is an async call, but you don't have to await it or
       | anything or mark it as being an async fuction, whathaveyou
       | 
       | effectively, we de-color the language:
       | 
       | https://journal.stuffwithstuff.com/2015/02/01/what-color-is-...
       | 
       | my feeling is that async concerns are too low level for light
       | scripting
        
         | zkldi wrote:
         | How would you allow running the fetches in
         | fetch /some-url as json         fetch /some-other-url as json
         | do_stuff_with(result1, result2)
         | 
         | in parallel?
        
           | recursivedoubts wrote:
           | hyperscript is focused on the common cases for light front
           | end scripting, so right now there isn't syntax for doing
           | operations in parallel.
           | 
           | If I needed that I would kick out to javascript and use
           | Promise.all() to return an expression that hyperscript could
           | then sync on
           | 
           | the wheelhouse for hyperscript is stuff like:
           | on load         wait 5s         transition my opacity to 0
           | remove me
           | 
           | where you don't have to do any async or callback stuff for
           | what are, at root, async operations.
        
       | z3t4 wrote:
       | I understand there are two sides/groups here: 1) Those who think
       | errors are important to control flow, and 2) Those who think
       | errors are exceptions to control flow. If you are in group 2 both
       | Promises and async/await will give you neat and simple code. But
       | if you are in group 1 Promises and async/await will be really
       | complicated and ugly because each await will be inside a
       | try/catch.
       | 
       | Because I'm in group 1, I try to avoid Promises (and thus
       | async/await) in JS because the promise will capture all future
       | errors, and if you forget to add a .catch, that error will never
       | surface. Promises make asynchronous code more complicated.
       | Async/await however get rid of a lot of the complicated syntax,
       | so when I do not care about errors (eg. errors are exceptions) I
       | use async/await because of easier control flow.
        
         | z3t4 wrote:
         | Those who think of errors as exceptions can further be divided
         | into group 2a) Those who prefer Promises syntax. And group 2b)
         | Those who prefer async/await syntax.
         | 
         | Also don't forget about co-routines:
         | co(function* () {             var user = yield getUser();
         | var comments = yield getComments(user);         });
         | 
         | Just replace "co(" with async, and yield with await, and you'll
         | have async/await.
        
         | jseban wrote:
         | Errors are an important part of the control flow, if you are
         | doing UI programming, which is what Javascript is made for.
        
       | qudat wrote:
       | I was really hoping this article would discuss the benefits of
       | using raw generators over async/await.
       | 
       | By using async/await, we are inherently limited by the flow
       | control because we are forced into await resolving promises.
       | 
       | This is why libraries like redux-saga[0] or cofx[1] use
       | generators.
       | 
       | https://redux-saga.js.org https://github.com/neurosnap/cofx
       | 
       | Generators provide much better flexibility over flow control and
       | allow us to treat side effects as data.
        
       | chmod775 wrote:
       | First off, async/await _is_ promises. It 's merely syntactic
       | sugar. The point of async/await is not to _never_ have the word
       | "Promise" appear in your code. It's also not meant to be
       | universally better than using Promises bare-bones.
       | 
       | A lot of the argument appears to be the author extrapolating from
       | his own lack of familiarity to others: "We are taught", "our
       | minds", etc. I can easily construe some hypothetical person with
       | a certain set of skills (and lack thereof) that would have just
       | as much trouble with bare-bones Promises. But I don't have to
       | because the author did it for me at "One more thing...".
       | 
       | "People can mess this up" was never an argument. You can mess
       | everything up. The more interesting question is how badly and how
       | often.
        
         | Waterluvian wrote:
         | TypeScript even forces you to acknowledge this as the explicit
         | return type of an async function is a promise.
        
         | phendrenad2 wrote:
         | > First off, async/await is promises. It's merely syntactic
         | sugar. The point of async/await is not to never have the word
         | "Promise" appear in your code
         | 
         | Sounds like you didn't understand the point of the article.
         | Unfortunately, you're arguing against something the author
         | never said, the author never said that async/await weren't
         | promises. You just got stuck on the fact that the author used
         | the term "promise" for the non-async/await style of code. I
         | understood what the author meant, anyway.
         | 
         | > "People can mess this up" was never an argument
         | 
         | Unfortunately, you're arguing against something the author
         | never said here, also. The author is saying that non-
         | async/await code is better code than async/await. Not that
         | "people can mess this up" or something.
        
           | chmod775 wrote:
           | > Sounds like you didn't understand the point of the article.
           | Unfortunately, you're arguing against something the author
           | never said, the author never said that async/await weren't
           | promises.
           | 
           | Well. I never said that I didn't understand the article.
           | Unfortunately you are arguing against something I never said.
           | Funny how that works.
           | 
           | > The author is saying that non-async/await code is better
           | code than async/await.
           | 
           | And what does "better" mean to the author?
           | 
           | The entire first section is devoted to the author talking
           | about criteria such as "brittle"-ness, "error-prone"-ness,
           | and "footguns".
           | 
           | You seem to be getting stuck up on the fact that the author
           | never used the exact same wording as I did.
        
         | spankalee wrote:
         | async/await is _safer_ too, because part of that syntactic
         | sugar is wiring up exceptions correctly and ensuring that a
         | function only returns or rejects asynchronously and never
         | synchronously. This prevents lots of bugs.
         | 
         | This article is bad, bad advice.
        
         | whatdidiexpect2 wrote:
         | It's just another willfully ignorant post by a mediocre
         | JavaScript developer. Are you shocked?
        
           | noahtallen wrote:
        
         | eurasiantiger wrote:
         | This, very much this.                   async function() {}
         | 
         | is much nicer than                   function() {
         | return new Promise(             (resolve) => resolve()
         | )         }
        
           | kabes wrote:
           | I agree but second one could just be `() =>
           | Promise.resolve()`
        
             | adamauckland wrote:
             | It could, but depending on how you use it, you're changing
             | scoping.
        
               | kabes wrote:
               | True. But these days it's rare to see a scope other than
               | what you'd expect from the short hand version. Old school
               | JS with plain prototypes and flexible 'this' scope is
               | very powerful, but is too hard to understand and thus
               | rare these days.
        
           | bin_bash wrote:
           | I prefer async/await but this is a contrived example.
           | 
           | For starters you can just write:                   const
           | myfunc = () => new Promise(resolve => resolve())
           | 
           | or                   Promise.resolve()
        
             | Aeolun wrote:
             | const myfunc = () => new Promise(resolve => resolve())
             | 
             | Is there anyone that actually likes this structure? I find
             | it really hard to reason about what a line like this does.
             | What is the upper limit on double arrows in one line?
        
               | albedoa wrote:
               | Your gripe is that there are two arrows on one line? The
               | second is an argument to the promise constructor. You
               | should be able to reason about this line easily.
        
               | bin_bash wrote:
               | here's a real world example I use all the time:
               | const wait = (ms = 500) => new Promise(resolve =>
               | setTimeout(resolve, ms));
               | 
               | then:                   async function () {
               | await wait(1000);         }
               | 
               | Perhaps it's hard to grok but it sure is a handy one-
               | liner.
               | 
               | Of course in newer versions of node we can now do:
               | import {           setTimeout,         } from
               | 'timers/promises';              await setTimeout(100);
        
               | love2read wrote:
               | this works in older versions of node too:
               | 
               | const wait = require('util').promisify(setTimeout)
        
               | oauea wrote:
               | but not in the browser
        
               | joe_guy wrote:
               | There's no merit of what should be a project wide
               | function being a single line instead of 3 to avoid "hard
               | to grok" syntax.
        
               | deschutes wrote:
               | Wait till you see the rest of javascript...
        
               | eurasiantiger wrote:
               | Your comment is snarky and categorically dismissive. Care
               | to explain why you have taken such an aggressive stance
               | against JS?
        
               | eurasiantiger wrote:
               | It's the cleanest way to wrap a event-emitting library,
               | for example. async/await is not applicable in such a case
               | where resolve needs to be explicitly called in a
               | callback.                   async function process() {
               | return new Promise((resolve, reject) => {
               | emitter.on("error", (err) => reject(err));
               | emitter.on("end", (result) => resolve(result));
               | emitter.start();           });         }
               | 
               | async is not strictly needed here, but I find it a good
               | practice to use it on functions which immediately return
               | a Promise anyway.
        
               | [deleted]
        
               | zkldi wrote:
               | I don't think it's a good practice, atleast if you have
               | typescript jn your stack. It's redundant and wraps the
               | promise in another promise.
        
               | eurasiantiger wrote:
               | IIRC that doesn't actually happen if a native Promise is
               | returned.
        
               | eyelidlessness wrote:
               | It does, but only if you also add a redundant await.
               | Which I still do, even in TypeScript, unless there's a
               | compelling performance reason not to. I disagree with the
               | article overall, but I do agree that making asynchrony as
               | explicit as possible is a good idea. Otherwise you end up
               | with code like:                 async function foo(bar) {
               | // ...       }            function nonObviousAsyncFn() {
               | // ...         return foo(quux);       }
               | 
               | Explicit return types would help, but most people don't
               | write them unless they're forced by a linter.
        
             | wildrhythms wrote:
             | As soon as you need to chain Promises, this gets very
             | annoying and you quickly find yourself in a nested callback
             | hell.
        
               | bin_bash wrote:
               | If you're nesting "new Promise" you're almost certainly
               | doing it wrong. This is for generating new promises not
               | executing them.
        
           | dataflow wrote:
           | new Promise() is not how you want to create a promise in JS
           | (except when you really have to), just like 'new'/'delete'
           | are not how you ant to allocate memory in C++ (except when
           | you really have to). There are lots of helpers in that class
           | that make promises significantly more ergonomic.
        
             | michaelsalim wrote:
             | Care to give some examples of the helpers? I always just
             | use new Promise()
        
               | aGHz wrote:
               | You really end up creating promises manually, the vast
               | majority are downstream from an IO call like fetch() or a
               | database query.
        
               | eurasiantiger wrote:
               | Many devs unnecessarily nest Promises like that.
               | async function getData() {           return new
               | Promise((resolve) => {             const res =
               | fetch(...);             resolve(res);           });
               | }
               | 
               | The response above is wrapped in THREE different
               | Promises! One from fetch, one manually created, and one
               | implicitly created by `async`.
               | 
               | The code above behaves exactly the same as
               | function getData() {            return fetch(...);
               | }
               | 
               | or even just                   fetch(...);
        
               | Cpoll wrote:
               | > function getData() { return fetch(...); }
               | 
               | I feel like there are advantages to making it `async
               | function`, even if it's superfluous, because it signals
               | to readers and to static code analysis that the function
               | returns a promise. That's assuming the return type of
               | fetch(...) can't be inferred by static analysis and
               | developer tooling.
        
               | Kwantuum wrote:
               | > the type of fetch() can't be inferred by static
               | analysis
               | 
               | That is preposterous.
        
               | Cpoll wrote:
               | It's not. One might assume it's Node fetch, but parent
               | post was just using a specific example to make a general
               | point. Fetch can be `any`thing.
               | 
               | Would you say the same thing about
               | 
               | function getData() { return mysteryFunction(...); }
        
               | RobertWHurst wrote:
               | I've been on teams working on node projects for like 15
               | years. I've never seen someone who understands promises
               | or async await do that. You'd have to know nothing about
               | what the async keyword actually does to be compelled to
               | do that.
        
               | hn_throwaway_99 wrote:
               | I mean, I know its a bit of linguistic flourish, but
               | considering NodeJS was only initially released 12 years
               | ago, that's quite a feat!
        
               | eurasiantiger wrote:
               | I have seen plenty of (usually junior front-end) devs
               | resort to exactly this kind of cargo cult coding and
               | magical thinking.
        
               | wiml wrote:
               | Well, they're junior devs. You're supposed to help them
               | get past that stage, not just throw away all your tools.
        
               | eurasiantiger wrote:
               | What made you think I haven't been helping them?
        
               | joe_guy wrote:
               | I'm going out on a limb here and assuming the issues with
               | their code don't begin and end with async.
        
               | cercatrova wrote:
               | > I've never seen someone who understands promises or
               | async await do that. You'd have to know nothing about
               | what the async keyword actually does to be compelled to
               | do that.
               | 
               | > usually junior front-end
               | 
               | So you agree with each other then?
        
               | eurasiantiger wrote:
               | Good day, axe handle.
        
               | garyrob wrote:
               | I'm a newbie with respect to JS and especially promises
               | and async/await, but I need to learn. If you could point
               | me to some resource that does a really good job of
               | explaining all this, I'd appreciate it very much. I
               | expect that I wouldn't be the only one. What's something
               | you'd recommend to a junior developer so that they
               | wouldn't be one of the "many devs", as you put it, who do
               | the wrong thing?
        
               | magnio wrote:
               | Not the parent, but I recommend understanding the event
               | loop first: here [0] is a very good talk. Then, read the
               | chapter on promise on javascript.info [1], as it explains
               | the problems Promise set out to solve (callback hell),
               | then as usual the excellent MDN article [2].
               | 
               | [0] https://www.youtube.com/watch?v=8aGhZQkoFbQ
               | 
               | [1] https://javascript.info/async
               | 
               | [2] https://developer.mozilla.org/en-
               | US/docs/Web/JavaScript/Guid...
        
               | stareatgoats wrote:
               | The whole async/await paradigm (including promises) is
               | trying to fit square pegs into round holes (trying to
               | make async processes look like they are synchronous).
               | Just look at the comments on this page; even though
               | async/await/promises have been around for years they are
               | still causing difficulties for even the most experienced
               | devs.
               | 
               | It doesn't mean it can't be mastered, it can, but the
               | whole paradigm is so fraught with pitfalls and conceptual
               | difficulties that an codebase that uses it in any
               | extensive way will forever be unstable. The whole thing
               | is supposed to help against callback hell, but that can
               | be better solved by a simple thenable object.
               | 
               | Not a popular opinion I know, but there you go.
        
               | doliveira wrote:
               | > simple thenable object
               | 
               | Wouldn't you simply be reinventing promises?
        
               | eurasiantiger wrote:
               | > trying to make async processes look like they are
               | synchronous
               | 
               | That is NOT what async/await is about -- after all, async
               | explicitly marks functions as asynchronous. Not exactly
               | trying to hide that.
               | 
               | Async/await is syntactic sugar. It is there to make
               | working with Promises less verbose.
               | 
               | That is almost all: await pauses current function
               | execution in the main event loop, which is an important
               | detail
        
               | lmc wrote:
               | This doesn't directly answer your question, but...
               | something to watch out for is experienced developers can
               | also struggle with promises and async code if they've
               | spent most of their career working with sync code. And
               | when we 'get' it, the difficulty of the journey is often
               | understated. This stuff can be _hard_ , so don't sweat it
               | if it seems frustrating. (On the other hand, it may be
               | easier if you don't have years of sync patterns to
               | mentally set aside )
        
               | savanaly wrote:
               | This is absolutely correct why is it being downvoted lol
        
               | Kwantuum wrote:
               | It really isn't, most native/standard APIs do not return
               | Promises. Lots of things use callbacks. Being comfortable
               | creating Promises from a callback-based API is definitely
               | something any competent JS dev ought to be able to do.
        
               | MrJohz wrote:
               | A lot of APIs produce promises these days. The big one
               | that I always need to promisify is `setTimeout`, but
               | apart from that, I tend to find that if I'm using the
               | `new Promise` API, I'm usually doing something wrong.
               | 
               | With Node APIs, there's a promisified version of pretty
               | much everything. With browser APIs, there's usually a
               | version with promises, and I'm struggling to think of an
               | asynchronous API without promises that hasn't been
               | superseded by something else (e.g. XMLHttpRequest ->
               | fetch). If I'm converting from an event-emitter API to
               | promises, there's usually going to be an impedance
               | mismatch between the expectations of the event-based
               | system and the promise-based system, and I probably need
               | to explore another option.
               | 
               | I agree that any competent JS dev should understand how
               | to create promises "from scratch" like this. But it still
               | should probably be a fairly rare occurrence, and if I see
               | a lot of `new Promise` calls in one place, it's pretty
               | much always a sign that someone doesn't really understand
               | how promises work.
        
               | lmc wrote:
               | Here's a few. The docs link to some others that may also
               | be useful...
               | 
               | Promise.resolve()
               | 
               | https://developer.mozilla.org/en-
               | US/docs/Web/JavaScript/Refe...
               | 
               | You can use this in place of new Promise() (though you
               | rarely need it, as an async function automatically wraps
               | any non-promise return value in a promise.)
               | 
               | ----------
               | 
               | Promise.all()
               | 
               | https://developer.mozilla.org/en-
               | US/docs/Web/JavaScript/Refe...
               | 
               | For making requests in parallel, and returning when all
               | have been successful.
               | 
               | ----------
               | 
               | Promise.allSettled()
               | 
               | https://developer.mozilla.org/en-
               | US/docs/Web/JavaScript/Refe...
               | 
               | For making requests in parallel, and returning when all
               | have completed whether successful or not.
               | 
               | ----------
               | 
               | Promise.any()
               | 
               | https://developer.mozilla.org/en-
               | US/docs/Web/JavaScript/Refe...
               | 
               | For making requests in parallel, and returning the first
               | successful response.
               | 
               | --------
               | 
               | As mentioned in sibling comment, things like fetch and DB
               | calls return promises anyway, so the above are mostly
               | only useful for working with multiple other promises.
        
         | mananaysiempre wrote:
         | > The point of async/await is not to _never_ have the word
         | "Promise" appear in your code.
         | 
         | Indeed it is not the point, and in that sense your criticism of
         | the article is correct.
         | 
         | However, there _are_ people who argue[1] that it is, in fact, a
         | good thing to never have the word  "Promise" appear in your
         | code, that _not_ having the freedom to execute whatever code
         | you want after launching an asynchronous operation and instead
         | having the predictability of always returning to the scheduler
         | makes reasoning about asynchronous code much simpler. (For one
         | thing, you can now reliably think--and have syntactic support
         | for thinking--in terms of sequential coroutines with
         | predictable yield points and known parents.)
         | 
         | In the context that Smith refers to (trio vs asyncio in Python,
         | regarding which also see the first, more Python-specific but
         | IMO better-argued post[2]) my experience actually bears that
         | out. How well this works given the historical API baggage in
         | JavaScript, I don't know, but probably not very well.
         | 
         | Another curious thing is that the line of research JavaScript
         | promises originate from[3] (Mark Miller co-wrote the spec
         | proposal IIRC) does not use them as the user interface;
         | instead, using the "eventual send"[4], you queue up method
         | calls to objects (which can be promised results of other queued
         | calls, and you may pass other promised objects as arguments).
         | 
         | I cannot clearly articulate the relation of this to Smith's
         | notion of "structured concurrency" (I wish I could), but in any
         | case it contributes some more weight to the opinion that the
         | ergonomics of Promises are indeed subpar. It might well be,
         | though, that in the context of JavaScript you can't actually
         | enforce enough structure on the preexisting APIs to build a
         | superior alternative.
         | 
         | [1] https://vorpus.org/blog/notes-on-structured-concurrency-
         | or-g...
         | 
         | [2] https://vorpus.org/blog/some-thoughts-on-asynchronous-api-
         | de...
         | 
         | [3] http://erights.org/talks/thesis/index.html
         | 
         | [4] http://erights.org/elib/distrib/pipeline.html
        
         | gotaquestion wrote:
         | > A lot of the argument appears to be the author extrapolating
         | from his own lack of familiarity to others
         | 
         | This is literally 97.5% of all tech blogs, and a disappointing
         | amount of content on HN front page.
         | 
         | I feel bad for the author. Nothing like asserting your
         | ignorance on a blog. There's a time and a place for literally
         | every language construct.
        
           | gompertz wrote:
           | Agreed, and I think some authors need to be more humble. If a
           | construct or design choice exists, its far more likely
           | someone (or a team) spent hundreds more hours intentionally
           | reasoning for its existence in the first place; over your
           | passive duration of usage.
        
         | BenoitEssiambre wrote:
         | Async/await is certainly not promises. In fact it would be much
         | better implemented without promises as I proposed here:
         | https://es.discourse.group/t/callback-based-simplified-async...
         | 
         | I would even say that async/await is anti-promise, it takes the
         | main functionality of promises, a caching layer for results and
         | errors that allows you to add the code continuation later and
         | elsewhere (which is a major footgun imo) and coerces the
         | execution flow back to going on the next line and provided
         | immediately at compile time which results in a cleaner flow but
         | not as clean, stateless, efficient or functional as if you were
         | to remove the promises completely. Having an additional caching
         | layer and state machine around every asynchronous function call
         | is quite inefficient.
         | 
         | The essence of async/await is not promises, it's the underlying
         | javascript generator (https://developer.mozilla.org/en-
         | US/docs/Web/JavaScript/Refe...) functionality combined with
         | asynchronous code to stop and start the generator. It's the
         | ability to pause and resume function execution based on
         | asynchronous operations.
         | 
         | The promise functionality, the caching layer and state machine
         | for results is basically sanitized away with async/await, it
         | becomes dead-weight computation. The only benefit of promises
         | in async/await code is being able to more easily interface with
         | other promise laden code which you don't need once you have
         | async/await and a library like
         | https://www.npmjs.com/package/async for more complex cases.
         | 
         | Note that promises based async/await is also a mess of an
         | implementation that breaks stack traces and needs to support
         | tons of odd statement corner cases (basically anything that can
         | return an object that could be a promise) whereas a
         | continuation passing style async/await would be a much simpler
         | implementation that would only apply to function calls and
         | maintain stack traces. We would get that stack trace support
         | automatically because of the great work of whoever implemented
         | javascript generators which seem to already carry stack traces
         | across paused/resumed functions (if you don't wrap in
         | promises).
        
           | nameisname wrote:
           | I don't agree with you fully. Async most certainly always
           | returns a promise and as such can easily be combined with
           | promise functions, like Promise.all. Your understanding of
           | stack traces on promises is also old/uninformed. I work on an
           | enterprise grade node app that was started back in node 0.11.
           | Bluebird, which was what one used, offers good stack tracing
           | and improved stack tracing has been available for async await
           | for a few years now. Infact, I don't think I have had to go
           | out of my way to get a decent stack trace in about a year or
           | more now. There are certain paradigms you can adopt that
           | keeps promise chains clean just like you would adopt with
           | callbacks. I can't comment on if async await was implemented
           | poorly as you are certainly more knowledgeable there with the
           | RFC you shared.
        
             | gorjusborg wrote:
             | Exactly. Async/await just an alternative way to represent a
             | promise chain.
             | 
             | My feeling is that mixing the use of promise chains and
             | async/await can make code hard to follow, so I ask
             | colleages to not mix them in the same function.
             | 
             | Sure, async/await is syntactic sugar for a generator that
             | chains promises into a promise chain for you. Not sure why
             | you'd care. That is an implementation detail that never
             | gets exposed to the user.
             | 
             | The only time I feel that promise chains are better
             | async/await is when treating Promise as a monad
             | https://blog.bitsrc.io/out-with-async-await-and-in-with-
             | prom...
        
           | [deleted]
        
       | anonymousDan wrote:
       | I don't find the first example convincing at all - to me await
       | clearly indicates you are going to be blocking until the result
       | arrives.
        
       | bsuvc wrote:
       | > I Avoid Async/Await
       | 
       | Tell me you're a difficult teammate without saying you're a
       | difficult teammate.
        
       | forty wrote:
       | I don't mind using async/await when I use promises, but in my
       | experience people who never worked with bare promises have a hard
       | time really understanding async/await and will eventually need
       | help from people who did for harder problems. Just like people
       | who never used callback flows often struggle to understand well
       | asynchronicity and mess up with promises.
        
       | emilfihlman wrote:
       | Promises are the most awful programming syntax I have ever come
       | across.
       | 
       | Await is sweet release from death as nowadays almost all apis are
       | forced onto promises. Thank god xhr and websockets came before
       | promises were mainstream, but for example webserial is absolutely
       | horrible to use.
       | 
       | Function callbacks are the best, though I wish JS would support
       | function scheduling.
        
         | dimgl wrote:
         | Who actually thinks like this?
         | 
         | Callbacks were absolutely unmaintainable. Promises (and
         | `async/await`) are really not that hard.
        
         | beebeepka wrote:
         | It's funny you say this because I have been promisifying xhr
         | for years until fetch came along.
         | 
         | And these days I do the same when I want to simplify WebWorker
         | communication. Promises are great
        
       | atsjie wrote:
       | I never liked promises when they were first introduced because I
       | never perceived this "callback hell" to be an unmanageable
       | problem; there are excellent libraries to manage callback
       | composition, e.g. https://caolan.github.io/async/v3/
       | 
       | When Promises came along I didn't feel they added much value; in
       | fact it made things more complicated (new paradigm, harder to
       | compose).
       | 
       | Still, I went with it because everyone else went with it.
       | 
       | Then async/await came along, I had the same issues as described
       | in the article. Most issues in the article I've made manageable
       | (learning patterns over time, using libraries and/or
       | conventions).
       | 
       | To me the article reads as someone who worked with async/await
       | for some time and never wanted to embrace and work with them in
       | the first place.
       | 
       | I'll be honest; if I'm working in a team with a collegue trying
       | to force all code to use promises instead of async/await I'd
       | probably ask him to stop doing that and escalate depending on the
       | response.
       | 
       | Being idiomatic is very important, it makes code recognizable for
       | newer devs. Had I stuck with callbacks until now I'd be writing
       | code few young JS/TS devs would understand or like to work on.
        
         | jrochkind1 wrote:
         | The semantics of the library you link to seems fairly
         | similar/analogous to promises to me! I'd in fact call promises
         | themselves "an excellent library to manage callback
         | composition", I don't see any reason to prefer the one you link
         | over the promises api -- even if neither were built-in to JS.
         | (And promises of course originally were not).
        
           | atsjie wrote:
           | Your comment is a bit misleading, I doubt you looked for more
           | than 30 seconds at that lib's documentation given the lack of
           | detail in your response.
           | 
           | Just to be clear; I would never use that lib in any
           | circumstance right now, I'd always prefer async/await for
           | idiomatic reasons.
           | 
           | But please have a look at
           | http://caolan.github.io/async/v3/docs.html#controlflow
           | 
           | Forever, queue, series, times, retry, until, waterfall,
           | whilst, etc etc... these are patterns that can all be
           | achieved with promises too but I am sure most devs will do a
           | google search before they do. In fact; some patterns are
           | better served by a library.
           | 
           | Only just yesterday I added
           | https://www.npmjs.com/package/p-limit to get concurrent
           | promise limitation behaviour; one of the many features of
           | that async-lib as well.
           | 
           | Don't misinterpret this as me suggesting these features
           | should be added to the standard; far from it. Community libs
           | do this job quite well.
           | 
           | I moved on from async, I moved on from Promises and embraced
           | async/await.
           | 
           | Do I like it? No, I much rather use Golang's channels. But
           | async/await is idiomatic and plenty of libs out there to
           | handle complex use cases.
           | 
           | Almost everyone has moved on, and anyone writing promises at
           | this moment is just creating legacy for anyone who is going
           | to maintain it. Is that a good reason in itself? No, but it
           | is a very valid one, that is my point.
        
         | [deleted]
        
         | jseban wrote:
         | Same here, I've never had that callback hell problem either, I
         | think it's pretty elegant actually and you can do a lot of nice
         | refactoring by extracting callbacks into variables. And the big
         | strength is that your programming actually looks the way that
         | the runtime works. It just becomes confusing with another
         | abstraction that obfuscates the way the runtime works and
         | requires you to now have this mental translation model.
        
       | namelosw wrote:
       | Async/await to Promise in JavaScript is just do notation to
       | monads in Haskell, what's the problem?
        
       | whatdidiexpect wrote:
        
       | unityByFreedom wrote:
       | I'll take "blog posts asserting silly things for clicks" for
       | $100, Alex.
       | 
       | All of this author's examples using .then() are single-line
       | functions. Seems contrived to suit their opinion.
       | 
       | Just use the right tool for the job.
        
         | pawelmurias wrote:
         | Just typical medium garbage with constructed examples to claim
         | that their artificial view point isn't _that_ stupid.
        
           | BigJono wrote:
           | You pretty much just described half the TC-39 proposals. I
           | _wish_ this shit was limited to noobs on Medium.
        
       | einpoklum wrote:
       | I like big promises and I cannot lie?
        
       | robmccoll wrote:
       | Everytime I use a language with async / await syntax, I find
       | myself wishing that awaiting async functions was the default
       | behavior and that I had to specify when I didn't want that
       | behavior. So much boilerplate, so many times I've seen bugs that
       | are the result of not being aware of a function being
       | asynchronous or that the function was later made asynchronous.
       | Most of the time you want seemingly synchronous behavior within a
       | request because it's easier to read, write, understand, and
       | reason about and concurrent progress across requests. The places
       | where I can overlap I/O within a request can be manually
       | specified. I guess this is kind of how Go works (although that's
       | parallelism and concurrency).
        
         | davidmurdoch wrote:
         | I like this idea!
        
         | chmod775 wrote:
         | You might be interested in these linter rules:
         | 
         | https://typescript-eslint.io/rules/no-misused-promises/
         | 
         | https://typescript-eslint.io/rules/no-floating-promises/
         | 
         | They can catch some common mistakes. Of course these checks can
         | only work reliably when you're using a typed language.
         | 
         | I'm still looking for one that forces me to put an await in
         | front of every function call that returns a promise, unless I
         | opt out.
        
         | oaiey wrote:
         | I actually start to appreciate function coloring in C# to never
         | forget that I am operating on asynchronous code. In .NET the
         | compiler also throws warnings if you do not await or pickup the
         | task/promise.
         | 
         | I also believe that you should see where asynchronous behavior
         | can happen in your code. So from that angle i also appreciate
         | the keyword and the coloring. Hidden resource access is pure
         | evil.
        
         | audunw wrote:
         | You may want to check out Zig's async/await. Seems to be closer
         | to what you're suggesting. It's one of the few implementations
         | where functions don't have an "async"/"no-async" color, and
         | where you use the same IO functions regardless of whether you
         | want to use them asynchronously or synchronously (if I remember
         | correctly).
        
         | [deleted]
        
       | whatdidiexpect2 wrote:
        
       | rootusrootus wrote:
       | Even though I feel competent enough using them, I continue to
       | dislike promises in any form, no matter how much syntactic sugar
       | there is.
        
         | beebeepka wrote:
         | I wonder what do you do instead.
        
       | cube00 wrote:
       | It's interesting using async/await, setting the target ES to be
       | an older version and watching how the TypeScript compiler
       | replaces async/await with yields and then no yields but a ton of
       | scary looking boilerplate as you progress further back through
       | older versions of ES.
        
         | Aeolun wrote:
         | Many awaits -> many, many case statements.
        
         | vbezhenar wrote:
         | Await basically splits function in two functions (before and
         | after) and uses second function as a callback for promise then.
         | Error handling makes it a little bit more complex, but not
         | much. Babel seems to make it harder than it needs to be, but
         | may be that makes sense from performance or maintainability
         | perspective.
        
       | todd3834 wrote:
       | Very strange to compare async/await to promises when it is just a
       | part of promises. There are rare situations where promise
       | callbacks might be easier to read but those are more edge cases
       | and a matter of personal preference.
        
       | parentheses wrote:
       | JavaScript Promises have their issues - the same ones all
       | asynchrony-providing libraries do. I feel the author takes a hard
       | stance on something quite nuanced.
       | 
       | Syntactic sugar hides the API, making it more ergonomic, also
       | leaking those problems. Same problem, different API
        
       | eurasiantiger wrote:
       | I stopped reading after the author made it clear they do not
       | understand async/await is merely syntactic sugar for Promises.
        
         | pelorat wrote:
         | Depends on the language. In C# they most definately not only
         | syntactic sugar.
        
           | dimgl wrote:
           | This article is on JavaScript.
        
       | [deleted]
        
       | tobyhinloopen wrote:
       | I avoid Javascript. Not because Javascript sucks, but most
       | libraries for Javascript suck.
        
       | valcron1000 wrote:
       | So "do notation considered harmful"?. Too bad that languages like
       | Haskell are not very popular. These kind of discussions feel
       | pointless.
        
       | fithisux wrote:
       | I use it in python and I love it.
        
       | darepublic wrote:
       | This take is garbage imo. Coming from someone who first used
       | jquery deferred, then native promises and now async await. If you
       | are too inexperienced to use await properly no reason to think
       | callback hell is going to make it better
        
       | mojuba wrote:
       | I know the article is about JavaScript, but I was wondering how
       | Swift resolves the problem of weak self within the async/await
       | model.
       | 
       | If the part of the function after await _is_ the callback, how do
       | I specify weak self if I need to?
        
         | ninkendo wrote:
         | You can generally do something like:                   Task {
         | [weak self] in             await foo()             self?.bar()
         | // self may be nil         }
         | 
         | That is, you can just make a new task which awaits on something
         | and then does more work, and that Task can be tagged with weak
         | self so that self can be freed.
        
           | mojuba wrote:
           | So basically no way to do the same with await, other than of
           | course declaring a weak local var.
        
             | ninkendo wrote:
             | If you're await'ing a variable directly in the same scope,
             | of course self will be retained, you're still running
             | inside self's scope.
             | 
             | I guess I'm confused by the question... if you want to
             | await something and allow self to be freed in the process,
             | you can use Task{ [weak self] } and then return early. If
             | you don't want to return early, you can't really release
             | self yet, since the scope shouldn't outlive self.
        
       | Go0the0gophers wrote:
       | Sure async/await makes your casde more complicated . That reason
       | why, I prefer use Go for I/O wait application because I don't
       | need to manage this Go doesn't it fore me. My code still readable
       | and simple.
        
         | vips7L wrote:
         | Until you need to do any error handling.
        
       | codecurve wrote:
       | > Give better cues that we are in an asynchronous mental model
       | 
       | The `async` keyword(!) is objectively a clearer signal that the
       | code in question is asynchronous. That's why type-checkers use it
       | to prevent you from doing dumb stuff like awaiting in a
       | synchronous function.
       | 
       | > In simple cases express the code at least as cleanly as
       | async/await
       | 
       | It's pretty hard to see much of an argument here. How can the
       | promise version ever be seen as "at least as clean"?
       | await someTask()         // vs         someTask().then(() =>
       | ...);
       | 
       | Even beyond the syntax here, the promise forces you into at least
       | one level deep of nesting, which instantly makes it much trickier
       | to manage intermediate variables, which either need to be passed
       | along as part of the result (usually resulting in an unwieldy
       | blob of data) or the promises need to be nested (pyramid of doom)
       | so that inner callbacks can access the results from outer
       | promises.
       | 
       | > Provides a much cleaner option for more complex workflows that
       | include error handling and parallelisation.
       | 
       | If you've somehow come to the conclusion that `Promise.all`
       | doesn't work with `async/await` then you have probably
       | misunderstood the relationship between `async` functions and
       | promises. They're the same thing. Want to parallelise a bunch of
       | `await` statements? You can still use `Promise.all`!
       | 
       | I do occasionally find try-catch to be awkward, but that's
       | because it creates a new lexical scope (just like promise
       | callbacks do). I also think the consistency from having one
       | unified way to handle errors in sync/async contexts justifies it.
        
       | zebracanevra wrote:
       | If you're doing nothing in between your async calls, using
       | .then/.catch might be simpler.
       | 
       | As soon as you need to introduce local variables and complex
       | control structures, not having shared closures between your .then
       | methods becomes extremely limiting. Hence, the async/await sugar.
       | 
       | About having to add await to ensure your error is handled with
       | the try catch -- _not_ putting an await before a promise is
       | something I use all the time. Being able to store tasks /promises
       | and reuse/await them later is a clear advantage to other types of
       | async code (such as coroutines).
        
         | Aeolun wrote:
         | > Being able to store tasks/promises and reuse/await them later
         | is a clear advantage
         | 
         | This sounds like horrible spaghetti. I can understand you might
         | need to do it in exceptional circumstances, but I wouldn't make
         | a habit of it.
        
           | zebracanevra wrote:
           | 99% of the time you'll be storing promises in order to await
           | on them in the same async method.
           | 
           | Those other 1% of times make for quite intuitive solutions, I
           | think. For example, a cache. Most caches are request =>
           | already finished response, but with a lookup of promises you
           | can easily do request => _in-progress_ responses, for de-
           | deplication.
        
           | yourad_io wrote:
           | Graceful shutdown & startup are two use cases that I used
           | this for, just today.
           | 
           | When my express server gets a SIGTERM I want it to stop
           | accepting new requests but finish pending requests before
           | exiting.
           | 
           | Likewise during startup, the HTTP server is currently up
           | before all resources are available - DB backends and the
           | like. So I await a .ready promise before all requests iff we
           | are not inited.
           | 
           | It can be abused into spaghetti for sure, but actual use
           | cases are not that exotic imho
        
         | madeofpalk wrote:
         | One thing I really like async/await for is you can use them in
         | for-loops. It makes it significantly easier to do async work in
         | what was previously very synchronous.
        
           | ElFitz wrote:
           | I thought await in loops was a big no no, unless it has
           | changed since I last checked?
           | 
           | Doesn't it remove any opportunity for parallelism, making the
           | loop take much longer than it would with a Promise.all?
           | 
           | Or am I missing something?
        
             | madeofpalk wrote:
             | You're right(ish) - the async functions would not run in
             | parallel. But sometimes that's either fine, or I don't want
             | them to run in parallel.
        
             | yourad_io wrote:
             | Sometimes you want to do things sequentially, so for..of x
             | { await } is the way to go
             | 
             | If you want parallelism: await Promise.all(x.map(...))
        
         | jonathanlydall wrote:
         | Completely my feelings too. He doesn't actually address this,
         | and it is actually the really painful part about promises which
         | async/await makes infinitely better.
         | 
         | I have had cases where converting .then(...) code to
         | async/await made the code infinitely easier to
         | understand/reason about and made it trivial remove bugs which
         | were present due to the complexities of dealing with control
         | flow logic.
         | 
         | It strikes me that the author is just already "used to"
         | promises and as such is trying to justify their preference for
         | them with examples which they believe "prove" that promises are
         | "better", but actually fail to do so. For every single one of
         | their examples, async/await is no worse, if not better.
         | 
         | For example, their argument about inadvertently serialized work
         | with the the two save calls. They are claiming that ".then()"
         | is more obviously serializing than the "await" keyword, which
         | is a highly subjective claim. If there is a problem here, it's
         | that some developers don't understand/know about all the
         | asynchronous tools which are available and so are unaware of
         | the option of using Promises.all(...).
         | 
         | Another argument for async/await compared to promises is the
         | following:                 try       {         await
         | doSomething();       }       catch()       {         // Do a
         | particular error handling for doSomething() failing       }
         | try       {         await doSomethingElse();       }
         | catch()       {         // Do a different particular error
         | handling for doSomethingElse() failing       }
         | 
         | What's the best way to reproduce this in promises only land,
         | for example, does the following work?
         | doSomething()         .catch(() => {           // Do a
         | particular error handling for doSomething() failing         })
         | .then(() => doSomethingElse())         .catch(() => {
         | // Do a different particular error handling for
         | doSomethingElse() failing         });
         | 
         | I _think_ it works, but I honestly don 't know for sure offhand
         | and to be sure I would need to check the documentation for
         | promises, whereas for the async/await approach, there is no
         | question. And if the above _doesn 't_ work, then I would have
         | to call the .then() from inside the first .catch() block, which
         | is awful code to read and interpret.
        
           | alerighi wrote:
           | It's the same code. Async/await is just syntactic sugar over
           | the promise syntax.
           | 
           | To me depends on what you are doing, there are cases where
           | using .then()/.catch() and .finnally() makes the code more
           | concise and simpler than using async/await.
        
           | beardedetim wrote:
           | .catch() returns a promise so you can call the then method on
           | it again, yes. If you throw from either catch or then it will
           | trigger the next catch method.
        
         | too_root wrote:
         | I agree. I think the article takes a simplistic view of the use
         | cases in an effort to make the post consumable but in doing so,
         | misses some of the point behind the syntax.
        
       | BillyTheKing wrote:
       | the whole blog-post seems a little constructed tbh - If I look at
       | await doSomething(param) await doSomethingElse(param)
       | 
       | the very first thing that comes to mind is that this can be very,
       | very easily optimised by just doing await Promise.all([
       | doSomething(param), doSomethingElse(param) ])
       | 
       | This is something I come across literally every day - why exactly
       | would that be an argument against async/await? much so on the
       | contrary, I find const myResult = await Promise.all([])
       | significantly more expressive, than
       | Promise.all([]).then(doSomething)
       | 
       | Also, as others have already pointed out - async/await is just
       | syntactic sugar around promises and can be used in addition to
       | 'normal' promise syntax (as shown above)
        
         | johnny22 wrote:
         | Once you're sure the operation doesn't need to happen serially
         | I hope :)
        
       | biglost wrote:
       | Maybe im wrong but i think await is not for everything it's
       | another tool, we as developer must known these tools, and when
       | its better to use it or no
        
       | jdrc wrote:
       | We need an AI to design a language that is optimal for humans to
       | program with. Languages should be designed by behavioral
       | scientists rather that computer scientists bcause their goal is
       | to adapt to the human rather than the machine. For example one of
       | the biggest limitations of humans is limited capacity of working
       | memory. Async paradigms exhaust this limit very early and lead to
       | frustration compared to serial programming. Writing one of them
       | in the form of the other doesn't solve any problem and is indeed
       | a travesty
        
       | manigandham wrote:
       | All async/await is built on promises/futures/tasks, which
       | themselves are built on yield/generators. Most modern languages
       | have converged on this and they are not different paradigms but
       | rather just newer syntax.
       | 
       | Async/await is better for expressing concurrent logic more
       | tersely and in the common "sync" format, and failure to
       | understand what it means is just that, a failure in
       | understanding.
       | 
       | There's no convincing argument here to use "promises instead
       | async" because it's the same thing.
        
       | STRML wrote:
       | > a try block in JavaScript immediately opts that section of code
       | out of many engine optimizations as the code can no longer be
       | broken down into determinative pieces
       | 
       | This isn't true and the dependent clause doesn't even make sense.
       | 
       | Yes, V8 had trouble optimizing try/catch back in the Crankshaft
       | days. But those days are _long_ gone, and major engines (V8
       | /TurboFan, JSC, and Mozilla's latest *Monkey) handle this
       | construct quite well. Even if this were not true, it would be
       | meaningless, as this is simply syntactic sugar over
       | `Promise#catch()`, which you would be using anyway.
        
       | zazibar wrote:
       | _Now maybe it's just my familiarity with Promises, but I look at
       | the third example and I can quickly see an opportunity._
       | 
       | This entire article is built around the author's ignorance and
       | could easily be summarised as "I avoid async/await syntax because
       | I'm more familiar with promises". The author doesn't even appear
       | to understand that async/await is syntactic sugar for promises.
        
         | codeflo wrote:
         | The author even implies in a footnote that switch statements
         | are unusable. I mean, we probably all had painful experience
         | with the "gotcha", and I appreciate efforts towards safer
         | designs. But I mean, let's not be ridiculous. It works fine.
        
         | gitfan86 wrote:
         | There is a growing trend where people just memorize how to do
         | things instead of understanding what those things actually do.
        
         | sidewndr46 wrote:
         | I did not take me long to reach the same conclusion. The
         | article can be summarized as "I am ignorant of the meaning of
         | async/await, thus I don't use it". This is perhaps one
         | incremental improvement from "I am ignorant of async/await,
         | thus I use it poorly". But in the wrong direction.
        
         | imtringued wrote:
         | What the author wants is something like this:
         | async {             save()             save()         } catch
         | (Exception e) {             console.log("Handle error")
         | }
         | 
         | async does not deliver this at all.
        
           | _ZeD_ wrote:
           | what the author wants doesn't exists because the two saves
           | will not actually run in parallel in any case. Not with
           | `async save(); async save();` nor with `Promise.all` nor with
           | any callback or any other means.
           | 
           | the author is conflating parallel with concurrent
           | programming.
           | 
           | and in (the mono-thread world of) javascript the two calls
           | will still occurs sequentially.
        
             | jjnoakes wrote:
             | This is only partly true, but misses the point.
             | 
             | Consider that 'save()' might do multiple steps under the
             | covers (network, database, localstorage, whatever).
             | Allowing those steps to run interleaved, if necessary (with
             | Promise.all), might be quite different from serializing the
             | 'save()' calls completely in the caller.
             | 
             | So while it is true that neither is truly parallel in the
             | "parallel vs concurrent" sense, it is not true that the
             | "sequential"/"concurrent" execution of both styles has the
             | same performance characteristics.
        
         | jrwr wrote:
         | I avoid Javascript outright because async/await/promise is
         | confusing to me. I blame it on being a PHP Programmer and likes
         | things to run serially.
        
           | bdcravens wrote:
           | It drove me crazy too, until I needed to use Puppeteer which
           | requires you to write async/await (there are Puppeteer
           | implementations in other languages, but they all seem to make
           | compromises I didn't want). Generally speaking, async/await
           | allows you to write code that looks and feels serial. Perhaps
           | try using one of the async libraries for PHP to wrap your
           | mind around the concept of async/await (like
           | https://github.com/spatie/async)
        
           | gorjusborg wrote:
           | I felt the same way coming from a threaded language.
           | 
           | Learning the event loop, then promises, then async/await is a
           | must. Today, you probably should throw typescript on top.
           | 
           | A steep learning curve just to get back to a typed language
           | that can do things concurrently.
           | 
           | You do get used to it, but it is a mess of stuff.
        
             | rwalle wrote:
             | This is ridiculous. Handling real threads is much more
             | complicated than handling async calls and the event loop of
             | JavaScript.
        
               | AA-BA-94-2A-56 wrote:
               | /r/gatekeeping
        
             | wonnage wrote:
             | Threads are their own steep learning curve, I think it's
             | just hard to do two things at once.
        
               | PaulDavisThe1st wrote:
               | It's easy to do two things at once when you can ask two
               | different entities to do them for you (threads).
               | 
               | What's hard is thinking about how to coordinate the work
               | they are doing for you: when to consider them done, how
               | to ask them if they did the work successfully, what to do
               | if they need to use the same tool at some point during
               | the work etc.
        
           | farmin wrote:
           | Hyperscript can help with this. https://hyperscript.org/
           | 
           | Makes using a bit of JavaScript relatively simple, just not
           | much in Stack Exchange yet which means reading docs..
        
         | snak wrote:
         | Agreed, I stopped reading after this sentence.
        
         | saimiam wrote:
         | I didn't read the article like that at all.
         | 
         | How would you handle two asynchronous saves which can happen in
         | parallel without using a Promise.all? Don't think you can...and
         | that's pretty much the entire point of the article.
         | 
         | Async/await is useless unless you are willing to serialize your
         | calls defeating the entire point of async code.
        
           | jffry wrote:
           | > How would you handle two asynchronous saves which can
           | happen in parallel without using a Promise.all?
           | 
           | This question doesn't make sense. Async/await is just a nicer
           | syntax for interacting with promises. So my answer to your
           | "gotcha" question is just:                 await
           | Promise.all([..., ...])
           | 
           | There's nothing impure going on here. The majority of the
           | time, async/await can make it much easier to see a code's
           | control flow by getting rid of most of the Promise related
           | cruft and callbacks.
           | 
           | I would call Promise.all a benefit here, as it makes it stand
           | out where I'm doing something in parallel.
        
           | rwalle wrote:
           | Wait, why _don 't_ do that? What's the point?
        
           | bilater wrote:
           | Yup - I prefer async/await but that was actually a good
           | example on optimizing multiple promises I had not though of
           | before.
        
           | jseban wrote:
           | Promises are also just syntactic sugar to make your code look
           | more synchronous, you can do everything with plain callbacks.
           | Which I find ironic with the article that he argues against
           | that but still just stops at the next turtle, instead of
           | following his own advice and actually learning how Javascript
           | and it's runtime works.
        
           | igemnace wrote:
           | Just because you use async/await doesn't mean you can't use
           | Promise.all.
           | 
           | In fact, my immediate intuition with the await examples _was_
           | to parallelize with Promise.all.                   await
           | Promise.all([/* build promises */]);
        
             | IshKebab wrote:
             | Yeah they had that in the post.
        
           | RedShift1 wrote:
           | const x = somethingAsync();       const y =
           | somethingAsyncToo();            return  { foo: await x, bar:
           | await y }
           | 
           | There is no point in returning one before the other because
           | you need both?
        
             | aGHz wrote:
             | But in JavaScript, these two awaits will not happen in
             | parallel, you really need to await Promise.all() for that.
        
               | [deleted]
        
               | tehbeard wrote:
               | You've really missed the point spectacularly of that
               | example.
               | 
               | Both those promises start, and both are waited for after
               | both have started..
               | 
               | That is the same as promise.all... There's just an
               | explicit order for the wait, rather than as they resolve,
               | but the result is the same.
               | 
               | Now, promise.any.... You'd have a point...
        
               | aGHz wrote:
               | This is correct, I wasn't paying attention.
        
               | linkdd wrote:
               | In Javascript, a Promise is started as soon as it is
               | created. In other words, this is not the `await` that
               | starts the Promise.
               | 
               | If the first await is the slowest, the second one will
               | return immediately (like calling .then on an already
               | resolved promise).
        
               | matt-attack wrote:
               | Pretty sure there can be unexpected behavior if you wait
               | too long before you do those awaits at the end.
        
               | RedShift1 wrote:
               | No, why would there be?
        
               | matt-attack wrote:
               | Node 16 will exit if an exception is thrown and not
               | awaited for some finite period of time. So if your goal
               | is to keep those promises in some cache and then resolve
               | them later on at your leisure, you will find the entire
               | node process will abort. There is a feature flag to
               | restore the older behavior but it's a pretty big gotcha.
        
               | RedShift1 wrote:
               | There is no such finite period of time. You can call an
               | async function and never await it.
               | 
               | Exception handling is something completely different.
               | Yes, if you call an async function and do not catch the
               | exception, Node will stop. But that is independent of
               | having called await or not. Whether or not you await
               | something async does not affect exception behavior.
        
               | codethief wrote:
               | +1 Notably, this is different in Python where promises
               | (futures) are executed lazily, i.e. when you await them.
        
             | saimiam wrote:
             | I think you're trying to recreate the semantics of
             | Promise.all without using Promise.all.
             | 
             | You're effectively saying that Promises are a better async
             | programming paradigm than async/await...which is also what
             | the author is saying in the article.
        
               | RedShift1 wrote:
               | I'm not saying anything about promises vs async/await.
               | The original comment said that you can't have 2 async
               | things happen in parallel without Promise.all, my code
               | snippet proves that you can.
        
       | divan wrote:
       | Author mentions that async/await messes up with mental model of
       | the code, and I think that's the most important issue with it,
       | but it goes even deeper than described in the article.
       | 
       | There are no inherently async or sync functions. It's not a
       | property of a function, rather the property of what caller does
       | after calling a function.
       | 
       | Is throwing a ball an async or sync action? Well, if tennis robot
       | machine spits one ball after another and doesn't care/wait about
       | feedback - then it's async. If the tennis player hits the ball
       | with a racket and puts all her/his attention into
       | waiting/validating the result (essentially blocking) - then it's
       | synchronous function. It's essentially an "attention" of the
       | caller that defines sync or async.
       | 
       | Marking code as inherently "sync" or "async" or claiming that one
       | functions are "hard" and others are "easy" is the single dumbest
       | idea I've seen in computer programming. And it's insane how
       | contagious it is - seems like languages are more often
       | copypasting features from other, instead of designing from the
       | first principles.
        
         | jffry wrote:
         | Since this article is specifically about Javascript: I think
         | the implementation of async/await in the language is heavily
         | constrained by a desire for backwards compatibility.
         | 
         | After all, async/await is ultimately promises all the way down,
         | so you can happily write code and let a compiler turn it into
         | ES5 that runs anywhere.
         | 
         | If instead JS allowed you to shunt arbitrary function calls off
         | into their own threads, then you would need bigger changes to
         | the engines to support that, and you couldn't back-port that to
         | vanilla javascript.
        
           | divan wrote:
           | To be honest, I find promises even worse concept for
           | concurrent programming. At least I never think about things
           | and behaviour in terms of "objects that will yield value in
           | the future". To use promises I need to build a layer of
           | conversion between "how my brain thinks about world" and
           | "passing around promises" - and that's just textbook
           | accidental complexity and unneeded cognitive load.
           | 
           | The least cognitively expensive model for concurrent
           | programming is CSP, precisely because it fits into how we
           | humans reason about world.
        
             | jseban wrote:
             | Me too, there is no concurrent programming in Javascript.
             | It's a continuation passing style language and a single
             | threaded runtime, I wish people would just spend a little
             | time learning how that works and normal javascript will
             | make a lot of sense and not look "yucky" anymore. And you
             | will realise how great of a fit that is for UI programming
             | and reacting to events from the user, where you don't have
             | to think about blocking the UI thread like you need to in
             | Java.
        
       | timcavel wrote:
       | This confuses async with parallelism, probably because JavaScript
       | is his threading model.
        
       | codeflo wrote:
       | Some language features aren't aimed at toy examples, and if
       | that's the scope of your thinking, you won't see the point.
       | 
       | For example, I like how the catch block is just a single function
       | call to handleErrorSomehow -- which would be totally fine for an
       | example, if it weren't for the fact that the author makes a
       | special note of how convenient it is that the Promise variant
       | reduces to just .catch(handleErrorSomehow). Suuuper-realistic.
       | 
       | I should probably admit that I also didn't completely see the
       | point of async/await -- this was years ago in C# -- until I first
       | had a chance to use it inside a complex loop of some kind. I
       | think it's a good exercise to try manually desugaring such an
       | example. It really makes you appreciate what the compiler's doing
       | for you in these cases.
        
       | jokethrowaway wrote:
       | Async / await is nice syntactic sugar. I don't understand why
       | they copied the naming from c# over do syntax in Haskell (which
       | dates roughly 1995, if I'm not mistaken).
       | 
       | The main problem is error handling, having to use try / catch is
       | pure cancer and really screw up your closure. You can use catch
       | together with await / async but then you're not dealing with
       | exceptions outside the promises.
        
         | frankincense wrote:
         | Typescript and C# are both developed and maintained by
         | Microsoft, and the lead architect of C# is also the creator of
         | Typescript. (Both great languages, IMO)
        
         | valenterry wrote:
         | async/await is not the same as the do-notation, that's why.
        
           | xigoi wrote:
           | How is it not?
        
             | valenterry wrote:
             | Many reasons, for example:
             | 
             | 1. do notation works and is used for any monadic type (e.g.
             | lists, parsers, promises, resources like database-
             | connection-contexts, ...) while async/await works for
             | promises only
             | 
             | 2. async works on the function-level and only there while
             | do-notation can be used in any place where a normal
             | expression can be used, including being abitrarily nested.
             | 
             | There are more differences, but that should be enough food
             | for the mind to think about it.
             | 
             | You could summarize it as: async/await makes it easier to
             | work with promises on the syntax level and trying to make
             | async code look like sync code, while the do-notation does
             | not try to make async code to look like sync code, but
             | rather embrace that sometimes two different semantical
             | flows are interwined (one inside a monadic context, one
             | pure) and makes it easier to work with them on the syntax
             | level while at the same time making the two look
             | _different_ explicitly.
        
               | xigoi wrote:
               | I don't think we disagree. JavaScript should've gone with
               | do notation precisely because it's a generalization of
               | async/await.
        
               | valenterry wrote:
               | From the perspective of someone wanting to use the
               | powerful do-notation, sure. But at the same time, the
               | hurdle for many developers who just want to "use promises
               | with ease", it would have been a steeper learning curve
               | with much less beginner-friendly syntax.
               | 
               | do-notation doesn't really help to deal with promises, it
               | even makes it harder because it is confusing at the
               | beginning. Async/await makes using promises easier and
               | hides problems for some time at least. I can see why they
               | chose to use async/await.
               | 
               | Just to give an example: error handling with try/catch.
               | That doesn't work with do-notation, but with async/await
               | you can integrate it (more or less at least) and it looks
               | like sync code.
        
       | gombosg wrote:
       | As a fullstack dev, I worked with
       | 
       | - Spring MVC (Java Futures)
       | 
       | - Spring Webflux (Reactor observables)
       | 
       | - Scala (Scala Futures & for comprehensions)
       | 
       | - TS async/await
       | 
       | - Angular observables
       | 
       | - React hooks (which combined with Redux, React Query etc. is a
       | special approach to async programming.)
       | 
       | I think it's very important to understand that ultimately, async
       | (non-blocking) programming is kind of a "hard problem" and there
       | is no trivial solution for it. But we can't get around it because
       | we must not block code execution: Javascript runtime environments
       | are single-threaded (except workers) and the JVM has limited
       | thread count, too.
       | 
       | Any senior developer has to understand how each of these
       | approaches work and how they are trying to solve the issue of
       | non-blocking code execution. I dare say that this problem area is
       | one of the hardest ones during becoming a more senior developer.
       | 
       | In terms of ergonomy (developer experience) when it comes to
       | simple chained non-blocking calls, in my opinion nothing beats
       | async/await in terms of syntax simplicity. I miss them from Java
       | & Scala! No indentation, lambda functions, flatmaps, monads or
       | special methods/hooks needed. You just have the result of an
       | async method right there.
       | 
       | I don't agree with the author that we shouldn't use async/await
       | because it _looks like_ synchronous code. We _should_ use it to
       | keep syntax simple and clean wherever possible!
       | 
       | The developer has to properly learn the language fundamentals
       | (and how JS code execution works) and know that async/await is
       | just syntax sugar over Promises and generator functions. If they
       | don't do this, then having a Promise.then() chain instead of
       | async/await won't help that developer write better code.
       | 
       | On the other hand, once they understand it, they can freely
       | choose between async/await and Promises depending on what needs
       | to be written.
        
         | mpweiher wrote:
         | > I don't agree with the author that we shouldn't use
         | async/await because it _looks like_ synchronous code.
         | 
         | Not having code that is actively deceptive sounds like a good
         | idea to me, so agree with the author.
         | 
         | > We _should_ use it to keep syntax simple and clean wherever
         | possible!
         | 
         | Having clean and simple syntax for async operations is a
         | laudable goal.
         | 
         | Having code that is actively deceptive about its semantics
         | seems less than ideal for accomplishing this goal.
         | 
         | Maybe we need to figure out new and different syntactic
         | constructs that are clean and simple, but do not pretend to be
         | something they are not?
        
           | wonnage wrote:
           | How are they deceptive? I don't know where the idea that
           | these keywords somehow mimic synchronous code comes from.
        
             | mpweiher wrote:
             | It's not the keywords that are deceptive. It's keeping the
             | rest of the code in a structure that is extremely different
             | from what actually happens.
             | 
             | https://dl.acm.org/doi/10.1145/3297280.3297528
             | 
             | "To solve JavaScript's callback hell problem, several
             | language mechanisms like Promise and async/await have
             | already been introduced to JavaScript. Using async/await,
             | which is the most promising one, callback hell code can be
             | rewritten to another simple and shallow nested code with
             | (almost) the same behavior. Unfortunately, however, it is
             | still difficult to precisely understand the execution order
             | of the rewritten async/await code, because the semantics of
             | async/await is difficult.
             | 
             | This paper first clarifies that this problem is caused by
             | the difficulty of the async/await semantics. Then, we
             | propose and implement a novel async/await visualizer called
             | AwaitViz, to support for programmers to understand the
             | execution order of async/await. Our contribution is
             | twofold. First, we show the feasibility of implementing the
             | visualizer AwaitViz based on source-code instrumentation,
             | which provides precise information on the JavaScript's
             | asynchronous behavior. Second, we show the difficulties and
             | limitations of implementing AwaitViz."
        
         | likeclockwork wrote:
         | You can't talk about async await without talking about try,
         | catch, and finally. I don't think async+await+try+catch+finally
         | is simpler than promises in any way.
         | 
         | I don't find anything simple or clean about imperative error
         | handling.
        
         | tm-guimaraes wrote:
         | Try ou kotlin coroutines. The suspend keyword really helps out
         | reasoning.
        
         | weinzierl wrote:
         | _" [..] and the JVM has limited thread count, too"_
         | 
         | I think I understand you point when it comes to the essentially
         | single threaded Javascript runtime, but the thread limit of the
         | JVM is huge, so how does that matter?
         | 
         | Not trying to be pedantic, just wanted to know if I missed
         | something.
        
           | gombosg wrote:
           | Yes, for JVM, it's not that trivial and non-blocking code is
           | definitely not mandatory. Our app backend has been written in
           | a blocking fashion and we are gradually transitioning to non-
           | blocking code.
           | 
           | Your question is very valid as the JVM can handle even
           | thousands of threads (given the host OS can).
           | 
           | Having less threads does keep memory usage lower (as each
           | thread in the thread pool has its own stack space). Also,
           | it's more scalable because if using blocking code execution,
           | you'll need to have one thread per concurrent request served.
           | Lastly, thread starvation can become a problem with blocking
           | code in case of delayed I/O or other failures. If that
           | happens, the server becomes unable to serve new requests.
           | 
           | See this SO answer: https://stackoverflow.com/a/63490797
        
       | imbnwa wrote:
       | Async/Await covers the 80% of use cases for async logic in JS.
       | Most people aren't really using promises as multicast references.
       | They don't call `then` in one place, hang on to the promise
       | reference, then call `then` again somewhere else (perhaps to
       | represent a cached value); they call `then` once on the reference
       | because it's just a moment in a composite operation.
       | 
       | It's for this reason that I think this library[0] is the more
       | appropriate abstraction for that same 80% of use-cases, as its
       | more memory efficient since you can represent the same composite
       | operation that generates multiple promise references with a
       | single object (a unicast reference instead). I haven't learned
       | Rust but apparently the author bases this on Rust's ownership
       | principle.
       | 
       | [0]https://github.com/mitranim/posterus
        
       | AshleysBrain wrote:
       | Their promise-based error handling seems to skip over a major
       | gotcha: if the first `save` call throws an exception, it does not
       | get handled in the `.catch()` callback! It would require its own
       | try-catch to handle. That is an overlooked benefit of try-catch
       | in async functions: it handles everything, both normal exceptions
       | and promise rejections.
        
         | Izkata wrote:
         | A rejected promise is passed along until it hits a catch. Both
         | save calls are handled by the one there.
        
       | LAC-Tech wrote:
       | I kind of agree. I learned promises from the promise API -
       | flatmapping over things, that will happen when the thing is
       | resolved.
       | 
       | I remember async/await was harder to grok because it seemed so
       | arbitrary. A bunch of syntax sugar, and function decorations..
       | promises were just method calls.
        
       | omgbear wrote:
       | For me, the key to async/await is a linter that complains about
       | un-handled promises. I appreciate in Go that any green threads
       | are created explicitly with `go`, whereas in typescript, they are
       | signaled by the return type.
       | 
       | My most recent background was in Go and so my mental model now is
       | that async functions are similar to goroutines and `await` is a
       | nice result collection mechanism.
       | 
       | What's recently confused me is that exceptions from yet-to-be-
       | awaited promises crash if you await anything else first.
        
       | vhakulinen wrote:
       | Regarding the error handling case, I've played around with the
       | idea of implementing a Result type with typescript and hiding the
       | errors behind that. The end result looks something like this
       | const res = await getJSON('/thingy');              if
       | (isErr(res)) {           // Handle error.           return;
       | }
       | 
       | You can read the details from here:
       | https://thingsthatkeepmeupatnight.dev/posts/simple-typescrip...
        
         | wereHamster wrote:
         | Congrats, you've re-invented sumtypes!
        
           | vhakulinen wrote:
           | Rather, copied over from other languages.
        
       ___________________________________________________________________
       (page generated 2022-04-16 23:02 UTC)