Earlier quoted context omitted.
Is the syntax composable? Can I do const json = await (await fetch(https://api.github.com/orgs/facebook')).json(); or do I have to name it?
What you asked for is whether `await` is idempotent. No it isn't. The "argument" to `await` is a Promise, and the "return value" of it is the resolved value of the Promise (i.e. `Promise#then`). EDIT: I missed the `.json()` part, but I suppose it doesn't return a Promise, no?
JavaScript async/await implemented in V8
201–210 of 227 posts
Re: JavaScript async/await implemented in V8
#202Earlier quoted context omitted.
Allow me to make both a theoretical and practical argument. It's been said that "callbacks are imperative; promises are functional". It's true. Furthermore, callbacks structure control flow and promises structure data flow. Instruction scheduling is an explicit sequence with callbacks (well, assuming the API calls you back precisely once), but scheduling is an implicit topological sort of the directed acyclic depende…
This is not quite true with regards to promises - one can do getY(x) .then(returnedY => Promise.all([Promise.resolve(y), zPromise()]) .then([y, z] => { ...another side effect...; return Promise.all([Promise.resolve(y), Promise.resolve(z), sideEffectPromise()]) .then([y, z, _] => f(y, z)); Not the cleanest, but you preserve the isolation without relying on polluted variables bleeding into function scope. In addition,…
2) catch's entire purpose is to be a catch-all for unexpected errors. For expected errors, it's better to have explicit error values. Bluebird.js at least lets you differentiate .catch from .error, where .error handles the explicit error values generated from traditional Node.js callbacks.
Re: JavaScript async/await implemented in V8
#203Earlier quoted context omitted.
This right here. One of my friends (a more experienced developer) told me at coffee one day, "I use const for everything" which really stuck with me. It really helps make it clear if you need a mutation to have let stand out.
I just wish let was in fact const (and something like "local" could be let), simply because the keyword let is nicer to type, easier to read, and more importantly better in line with the meaning of let in Lisp/Scheme/ML/OCaml/et al.
Re: JavaScript async/await implemented in V8
#204Earlier quoted context omitted.
"Pyramids" are not that useful for complex flows, just as synchronous-looking code, but for something as simple as your example they are equivalent in complexity, maybe even less complex, because they don't have additional implicit behavior introduced by async/await. Still, worlds better, than CSP with channels.
async/await ends up being the less complex thing, my "simple" example is an extreme that sometimes but rarely happens. When was the last time you saw that in synchronous code? It happens, certainly but the synchronous default is to only handle what you can handle and then pass everything else back up the chain. The asynchronous default with async/await is the same, and you can rely on default error propagation in the…
So, the equivalent to that code with callbacks is the one from your previous example and not the simplified one that doesn't handle errors. Not forgetting "if (error)" in this case will be exactly the same, as not forgetting "catch (error)" or "if (error)" if you handle errors properly in the first place. But these are just patterns and with enough consistency they don't introduce much cognitive load. What does is implicit behavior and you don't have one with callbacks in your example, but you do with await. It's not as bad, as with threads, but still a little bit worse, than with callbacks.
Re: JavaScript async/await implemented in V8
#205Earlier quoted context omitted.
async/await ends up being the less complex thing, my "simple" example is an extreme that sometimes but rarely happens. When was the last time you saw that in synchronous code? It happens, certainly but the synchronous default is to only handle what you can handle and then pass everything else back up the chain. The asynchronous default with async/await is the same, and you can rely on default error propagation in the…
First of all, exceptions are not a great way to handle errors, because they are implicit. There is no special keyword, like "await", to permit a function to throw exception, you have to guess an implicit behavior of each function. And you will have functions that never throw exceptions, functions that do, functions that lie about whether they do or do not. You will have to remember that at all times and be very caref…
«So, the equivalent to that code with callbacks is the one from your previous example and not the simplified one that doesn't handle errors.»
No, it isn't. It really isn't. The callback version isn't doing any sort of handling of errors, it's just laddering them, passing them back up the chain. The async/await version is doing the same automatically, wiring together for you the error handling to pass errors back to calling functions.
Even if you did want to handle every possible error/exception that could be thrown in doTheThing(), you don't really have to go all the way to the "parade" version, as only one try/catch should be sufficient in doTheThing().
The issue here is that where you see error handling as a cognitive load, the general best practices for error handling have mostly leaned to the goal that exceptions are for actual exceptional cases and catching exceptions should be left to cases where the user can actually fix the exceptional situation (rare) or logged somewhere appropriate in a global handler.
If you are unsure if you should handle an exception, don't handle the exception. Let the calling function catch, or let it continue bubbling up to whatever global exception handlers you want to set, or even just leave them for the browser's Unhandled Exception Handler and Unhandled Rejected Promise Handler to spit out debug information in its dev tools console. Don't bother remembering anything, just let your tools do their job.
The difference between catch (error) and if (error) in the callback example is that if you "forget" catch (error), it bubbles up to your browser's handlers, but if you forget if (error) it doesn't stop execution, it doesn't bubble up to your global toolkits and exception handlers and it doesn't bubble up into your dev tools debuggers.
(One thing I realized in writing this: due to my rustiness in callback coding I forgot that they should be if (error) return callback(error, null) to properly stop execution, which you want in the default case of not handling the error but passing it back up the chain. Small mistake that could cause debugging headache and adds to my point that the little things that are easy to forget that you always must do in the callback world can have a major impact on debugging...)
Re: JavaScript async/await implemented in V8
#206Earlier quoted context omitted.
> although technically you can change the data, just not the reference This is why I'm hoping to see native JS immutable data structures eventually (maybe it's already in a proposal somewhere?). ImmutableJS and Mori are great, but having a native solution that's available everywhere would be ideal.
Consider looking at other languages. ClojureScript does a pretty good job at immutability, Elm is great for immutability + strong typing, and PureScript adds in Haskell's advanced type system (typeclasses, HKTs, etc.)
Re: JavaScript async/await implemented in V8
#207Earlier quoted context omitted.
Fetch does have streaming uploads and downloads, and a quite some other features which doesn't come with xmlHttpRequest. Making it not strictly inferior to XMLHttpRequest
Will have. Future tense. Not present tense.
Re: JavaScript async/await implemented in V8
#208Earlier quoted context omitted.
> (e.g. multiple concurrent calls via Q.all, multiple "returns" via callback arguments) How about: async function main () { try { const responses = await Promise.all([ fetch('https://api.github.com/orgs/facebook'), fetch('https://api.github.com/orgs/facebook') ]); const jsons = await Promise.all(responses.map(res => res.json())) } catch (err) { console.log(err) } } I think this is pretty clear and not needing any lib…
I will admit that I hadn't realized async worked on Promises. This is definitely a very clean solution, though not one that can be seemingly achieved without Promise.all. There is, of course, no library needed to use pure promises for the same functionality, though. My point is that all of this is possible without async/await, which to me are abstractions that cloud the landscape, obscuring the real evented nature of…
Re: JavaScript async/await implemented in V8
#209The moment I started using async await (with babel) combined with the new fetch API so many libraries got obsolete. Getting data is as easy as: async function main () { try { const res = await fetch('https://api.github.com/orgs/facebook'); const json = await res.json(); console.log(json); } catch (e) { // handle error } } So I am quite happy when this lands in modern browsers asap.
Re: JavaScript async/await implemented in V8
#210Earlier quoted context omitted.
"Pyramids" are not that useful for complex flows, just as synchronous-looking code, but for something as simple as your example they are equivalent in complexity, maybe even less complex, because they don't have additional implicit behavior introduced by async/await. Still, worlds better, than CSP with channels.
async/await ends up being the less complex thing, my "simple" example is an extreme that sometimes but rarely happens. When was the last time you saw that in synchronous code? It happens, certainly but the synchronous default is to only handle what you can handle and then pass everything else back up the chain. The asynchronous default with async/await is the same, and you can rely on default error propagation in the…