7 ms·
I heard Doug Crockford talk about how he doesn't think async/await is that great an idea on a podcast a while ago. His argument was that it's an unclean abstra
by davnicwil 9y ago
I heard Doug Crockford talk about how he doesn't think async/await is that great an idea on a podcast a while ago.
His argument was that it's an unclean abstraction - it gives you access to 'features' of synchronous imperative syntax (lines in a function always execute in order, try-catch blocks, etc) but it remains conceptually and literally promises all the way down.
Therefore, all await 'calls' are really non-blocking at a global level, yet they appear blocking to the local lines of code inside the same async function. This is liable to cause confusion - particularly for beginners or occasional visitors to JS who don't fully grok or have the concept of promises top of mind - but really for everyone.
I've used async/await a fair amount in production code now (with babel) and while it does make some code a bit cleaner, honestly it is often to the detriment of understanding it when you come back to that code it in a few weeks. I've made plenty of stupid mistakes where the two 'faces' of the abstraction don't marry up, and it's frustrating.
More and more I'm inclined to just use promises, even when I have the choice of async/await - call a spade a spade and get on with your day. The article talks about promise chains getting complex and hard to read. Well, if this is the case, maybe it's your code or logic flows in general that need to be cleaned up, and changing the syntax to flatten the structures is actually just a sticky plaster over that.
- lexicality 9y ago> I've made plenty of stupid mistakes where the two 'faces' of the abstraction don't marry up, and it's frustrating. Would you mind sharing any of these?
- davnicwil 9y agoI'm talking really stupid, small, frustrating things, mostly at the interfaces. I read a return x at the bottom of one function and call the function elsewhere and try to use x, but oh wait no.. it was an async function so I've really got Promise<x>. Generally it's just because of the leaky abstraction making very fast mental mapping of code a bit harder.
- hdhzy 9y agoAnother common mistake is accidentally not awaiting a function that returns a promise. That makes some really hard debugging (race conditions) as this issue is not caught even by TypeScript.
- wahern 9y agoHere's a great article somebody posted on HN awhile back, "What Color is Your Function?" -- http://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/ http://journal.stuffwithstuff.com/2015/02/01/what-color-is-y... The proper abstraction is threads--i.e. a stack structure used for the storage of temporary values, which is shared by nested function invocations as well as similar structured programming constructs like if/else conditionals that together represent a singular thread of control through the program as it processes data and events. "Thread of control" is precisely what you're cobbling together with promises, async/await, etc, using clunky compiler constructs bolted onto the language model and implementation. The problem is that we conflate the implementation with the abstraction, sometimes by necessity (the legacy of the contiguous, so-called "C stack") but usually unnecessarily. It pays to remember that some operating systems, such as some of IBM's mainframe platforms, IIRC, implement a thread stack as a linked-list of invocation frames, rather than a contiguous array. But it's completely transparent, as it should be. Async/await does the exact same thing, except it's not transparent as it should be. So now you have _two_ distinct, mutually incompatible kinds of functions solely because the implementation is unable to properly hide the gory details, which is ludicrous on its face.
- aidenn0 9y agolight-weight multithreading that enters a scheduler loop when I/O would block is great, and I haven't seen any advantages of async/await compared to that, other than ease of implementation (you make the programmer or library author implement multithreading, rather than implementing it in your runtime). Promises are at least slightly more interesting because they can functionally compose in various ways (but most of the time it's just a dozen then() calls in a row, and threading would have been better).
- wahern 9y agoThere are definitely patterns where a Promise API is more readable. You can implement a Promise API with or without separate threads, but if you execute it on a separate thread the number of library calls the Promise function can make isn't limited. FWIW, I'd be careful about conflating issues such as how to handle I/O. Threads don't imply preemptive scheduling. Lua coroutines are implemented as threads, but that's the extent of things--there's no builtin scheduler or event loop nor features specifically directed toward implementing those things[1], just coroutine.resume and coroutine.yield. (yield can be called from any function at any depth as long as the call stack is on a coroutine thread, which in Lua is every stack except the main one.) And that's fine by me. The most fundamental issue from the perspective of the language design is about how to represent a thread of control that is consistent with the other structured programming constructs like function calls. A batteries-included event loop or a preemptive scheduler are nice to have, but notably they're much easier to implement (internally or third-party) and use if you have a thread construct. [1] Debugging hooks notwithstanding.
- thinbeige 9y ago> honestly it is often to the detriment of understanding it when you come back to that code it in a few weeks. Not in my case. I think async await makes everything quite clear BUT you have to understand promises and async await well. This stuff ia super tough and I needed a week or more. Then you can produce quite elegant code.
- davnicwil 9y agoMaybe I didn't get this across but I do understand async/await and promises well, and that's kind of the point - it's still troublesome at times for me to understand at a glance once I'm out of the context of the code.. precisely because it's a slightly unclean abstraction.
- BoorishBears 9y agoIt's funny watch Js go through the motions C# did with TPL and Async/await. The same exact arguments and pitfalls coming up
- billytetrud 9y agoI use the futures from node-fibers all over the place in my backend code. It has possibly only once caused me confusion over something. If you're writing your code right, it shouldn't cause confusion. You don't need to make your code ugly to understand when things are asynchronous.