Microsoft Edge gets native ECMAScript 7 async/await support in latest build
blogs.msdn.com
blogs.msdn.com
...which is cool, because using async/await in C# made me realize how much simpler dealing with async code could be (compared to my experience with JS callbacks or Java threads).
http://blogs.msdn.com/b/vcblog/archive/2014/11/12/resumable-...
What does streaming APIs have to do with CSP per se?
Could you expand on in what way you think async and await is insufficient with regards to streams? I'm genuinely curious.
I'm interested to see what it looks like.
NDC posts their videos online after each conference, and I did a quick skim. I think it may be this session here, but I haven't double-checked:
Edit: It was a 2-part session and it may also have been in second half. Link here:
Go's model doesn't give you as much control over which thread a particular operation gets assigned to. It's not theoretically impossible, I suppose, but it's hard to imagine what a simple API for it would look like.
But yes, if this particular problem were solved in an elegant way, I would also prefer the CSP model. It makes it so you don't have to worry about which operations are async or not.
In any case I suppose many styles of Go program will exhibit accidental determinism, but it still seems too difficult to depend on as randomness can be introduced simply by invoking the wrong function, or by using a different runtime version, which to me feels comparable to the hazards of raw multithreading.
While async/await allows for an abstraction over the lower level tasks, that are still exposed, in case one needs more control over the threading runtime.
For example, in JS's case you can still dig into the Promise world if needed.
Similarly in C#, Tasks / Dataflow and SignalR can also be used.
Whereas in Go, correct me if I am wrong, outside CSP one needs to reach out to threads/mutex/semaphore directly.
I'm not sure I understand your sentence. Are you saying that communicating sequential process only works because it is first class in Go or that CSP is not a solution to every concurrency problem ?
I tend to use languages that give library writers (almost) the same control as the language itself has.
EDIT: To expand a little more into what I mean. In most languages that offer async/await, that is mostly syntactic sugar (with some compiler help) to the blessed task pool library.
A good way to explore that is to see the parallel libraries available in C++, JVM, .NET, Haskell and OCaml worlds.
var orders = await getJSON('/users/joe/orders');
No callbacks, promises etc (Edit: that you have to look at, as other posters note the implementation uses promises in the background).You still have to explicitly say you want to be async, so it's not quite as good as non-blocking IO in something like Elixir, but it's the future as far as JS goes.
The similar line they use in their examples doesn't define a separate getJsonAsync function in the "Asynchronous city" section (and, as far as I can tell, there's no native getJSON function). That, and the fact that the line immediately preceding the await call has a comment that says, "just have to await the promise!", leads me to have to assume they used the function defined in the promises section, which of course uses promises. And, in order to define that promise, they do have to use three callbacks.
With functions and just callbacks I can make one-liners for fetching data too if I abstract away all the stuff that actually does the fetching of the data:
getJSON('/users/joe/orders', function(orders) {} );All async functions return promises, and all await expressions await on promises. Currently on babel implementation with facebooks's regenarator it seems to work on any "thenable", because I got it working with jquery and angular promises.
Promises are sufficiently supported in the latest versions of all major browsers, and Generators are almost there. They're supported in Firefox and Chrome, behind a flag in Edge, but unsupported in Safari.
But if you're targeting Node 4.0, you might as well transpile down to ES6 instead of going all the way to ES5 and pulling in Regenerator :)
There is a standard, native fetch() function which is pretty darn similar: https://hacks.mozilla.org/2015/03/this-api-is-so-fetching/
Which is unfortunate because async/await only works with promises, and if you want any other async model (like one that doesn't eat errors all the time) you can't use it. Luckily, generators are fine.
Basically, implementations log the error to the console and raise the PotentiallyUnhandledRejection event if an error occurs inside a promise and no .catch handler was attached. If a .catch handler is attached _after_ the error is already logged, then a RejectionHandled event is raised. You can listen to those global events (the context is process in node, and window in browser, I think).
0: https://github.com/domenic/unhandled-rejections-browser-spec...
This is the same as saying that "arrow functions only works if you want to represent functions".
Also, promises don't eat errors. It's the code using those promises that forget to handle them.
The async/await fixes that by unwrapping those errors for you. Any errors in an "await expression" will be thrown as exceptions up the stack.
Promises are not the only way to do async work in JS, as much as some people like to say that. You have observables and channels, which are more powerful because they handle streaming.
There are proposals to make async/await more composable: https://github.com/jhusain/compositional-functions. TC39 is aware of this but I'm not sure if they are going to fix it or not.
> Also, promises don't eat errors. It's the code using those promises that forget to handle them.
They literally do. They run your code in a try/catch block and store the error away, and you have to remember yourself to manually throw it later. You shouldn't be forced to run code inside a try/catch. http://jlongster.com/Stop-Trying-to-Catch-Me
As for the errors, I see what you mean. But at the same time this is an issue with trying to write async operations with sync constructs, something all "old" languages need to do. Async/await is a pattern that does that in languages that can't do it implicitly by requiring an explicit declaration. You don't need to write try/catch with async/await. You will get the exception propagated through the stack automatically.
Also, there is fundamentally nothing wrong with a promise error that never gets handled. It's an "if a tree falls in the woods" kind of thing, no? I will concur that it's not exactly beginner-friendly, though.
You should stop caring about that and start caring about the other stuff.
"Breakpoint on exception" still works, albeit slightly altered, and in any way it's a minor detail compared to the far better mental model for code execution that async and promises bring.
>I want to make stupid typo errors and have them appear as normal errors, not caught by promises.
For stupid typo errors use a linter and/or a transpiler like babel in the first place.
>It's cool, I just don't understand why everyone is so excited about a simple syntactic improvement.
Because better syntax brings code closer to how we think, and reduces errors.
The compiler probably does that for you, honoring catch blocks. It does in C#, I see no reason why it wouldn't in ES7.
So, async/await is actually less likely to eat exceptions.
Let me just try and translate that into sync-land: "Single value variables are not the only way to do work in JS, as much as some people like to say that. You have arrays and queues, which are more powerful because they handle multiple values"
(my point being, different abstractions are useful for different things and/or in different ways)
> There are proposals to make async/await more composable: https://github.com/jhusain/compositional-functions. TC39 is aware of this but I'm not sure if they are going to fix it or not.
I agree, but I don't think we need async/await at all. http://spion.github.io/posts/es7-async-await-step-in-the-wro...
> You shouldn't be forced to run code inside a try/catch.
How is throwing on typos useful? The real solution for that isn't letting errors get through. Its having a type system like TypeScript or Flow plus using a sensible library like bluebird that reports rather than swallows up unhandled errors by default. Afaik errors from native promises are reported to the console in most browsers. And there are also tools like this: https://github.com/emberjs/ember-inspector/wiki/Promises-Tab
Allowing thrown errors to propagate synchronously will destroy many contractual guarantees that make promises useful in nodejs. For example, we would have to remove this entire section in Bluebird: https://github.com/petkaantonov/bluebird/blob/master/API.md#... and instead fall back to process crashing and restarting. Lack of error catching is what makes node unable to provide a safe solution to the crashing problem (and domains capture errors in both directions of the call stack which leads to problems inside node internals). Promises neatly solve that by providing a sensible error capturing and propagation model that isolates node internals from promise code: https://github.com/petkaantonov/bluebird/issues/51
Browser native Promises and their corresponding Dev Tools work exactly how you would expect and surface uncaught exceptions in Promises. Browsers that support async/await will especially be incentivized to provide strong asynchronous exception handling in their Dev Tools.
It's just tough to polyfill that behavior without bringing the JS synchronous code world to a halt. A good Promises library/polyfill will at least attempt to console.log uncaught exceptions when they happen.
// this
var x = await promise;
callSomething(x);
// translates as
promise.then(x => callSomething(x));
Under the hood, the entire "async" function is turned into a state machine instead of creating a lot of callbacks. It's more efficient it can do some optimizations that would be boring to do manually.For example, if the translation were simply "turn into callbacks", this:
var p = getJson();
var x = await p;
var y = await p;
var z = await p;
would translate to something like : var p = getJson();
p.then(o => { var x = o; });
p.then(o => { var y = o; });
p.then(o => { var z = o; });
but instead, the code runs more like this: getJson().then(o => {
var x = o;
var y = o;
var z = o;
});
I say runs like because the compiled code is more complex than that, it will still call functions, etc. It will also handle exceptions, which would add a lot of boilerplate to this code. But have in mind that because this is generated by the compiler, this code will in most cases be more efficient than anything you try to write by hand.So conceptually, it's what I described; but in practice, it's optimized?
while (somecondition) {
try {
await sleep(1000);
somecondition = await someAsyncAction();
} catch(err) {
}
}
Doing retries, or loops against promise actions are really cumbersome with promises directly, but with async/await becomes much more clear in terms of action and intent. function iff(condition, method) {
return Promise.try(condition).then(result => {
if (result) {
return method();
}
});
}
function whilst(condition, method) {
return iff(condition, () => {
return Promise.try(method)
.then(whilst.bind(null, condition, method));
});
}
whilst(someAsyncAction, Promise.sleep.bind(null, 1000))
.catch(err => {
// ...
})
Naturally you wouldn't want to re-implement all of this control flow every time you need it. But the end result is not too much boilerplate. try {
await do_thing();
} catch {
// works
}The fact that you call a method that returns a promise but don't check this promise may be a little confusing to someone new to the language, but it it's not a flaw in the design.
In c#, any attemp to call a method that returns tasks (promise) without an await or a .continueWith (.then) causes a compiler warning. It's just a matter of time for tooling in the browser to keep up.
I don't think you're right, unless TC39 has changed their minds. I argued hard for a top-level `await` but was strongly fought back.
If you can call into an async function in a way that immediately throws errors (that means that we can literally check the stack if the current async function should just throw the error), then I'm all good.
You have exactly the same issue with setTimeout. Errors will be thrown when the function runs, not when you schedule it. The problem you're describing is not an issue, and that's why today there are linters and compilers.
If you're writing a library, use the runtime option. If you're writing a website or other standalone app, you should use the polyfill (especially if you use other libraries like React which depend on ES6 globals too).
This means you can get await-like promise handling in Node.js using the --harmony_generators flag.
[1]: https://github.com/ubolonton/js-csp [2]: http://taskjs.org/ [3]: https://github.com/tj/co [4]: https://github.com/bjouhier/galaxy [5]: https://github.com/creationix/gen-run
Edit: it appears that the caolan async lib came out after yours. Sorry for the confusion.
Your first commit was that January and Caolan's was that May, and when yours was "out" is debatable anyway since you don't have any releases tagged.
I would hardly feel obligated to rename a project over a 4-month-old Github repository that doesn't even target the same platform (Firefox vs. async being originally Node-only).
Which argues that async/await might not be what we really want in the end. As a user of Promises and async/await in the future, it's a very interesting read!
Even in Java UI frameworks like on Android or Swing, you have an event loop with a single thread, and when spawning another thread you have to deal with special communication layers [1]. True multithreaded UI's seem like an area for research.
[1] https://developer.android.com/training/multiple-threads/comm...
https://github.com/koajs/compose/pull/27#issuecomment-144868...
async/await is important and highly desired by the community, but I would prefer if it were not Microsoft trying to blast ahead and create yet another separate fragmentation between browsers. Sure they call it an experimental feature, but how long until they decide, "well we're not going to wait for this to get finalized, we're releasing it for everyone!!!" ?
Still a ways to go, though...
As a side note, I don't like how async/await has to be wrapped in try/catch AND a function for proper error handling
(async ()=>
try {
let result = await fetch('/file.json');
let json = await result.json();
console.log(json):
} catch(error) {
console.error('Not sure fetch failed or toJson');
}
)();
if you want to handle each error separately you need even more try catch!As for the try catch, you don't NEED to wrap. The sample just shows you can. You can't do:
try {
promise.then(() => ...);
} catch {}
but you can do try {
await promise;
...
} catch {}
async/await is a way to write simpler code the same way you would use a "for" block instead of a "while(iterator.next())" - because it's easier, all the rest is still the same.Of course, the same way you need to add a second callback to a promise handler if you want to handle errors. There is no difference, really. You're just changing the way you write the code.
Also, you're not forced to choose "await or promises". You can use both as you see fit, in the same block:
async () => {
// make 2 requests in parallel
var p1 = fetchSomething();
var p2 = fetchAnotherThing();
// wait for both of them to be done
await Promise.all(p1, p2);
// continue when they're both resolved
// these "await" only get the values since the promises are resolved
doSomethingWithTheValues(await p1, await p2);
}
> But for sync functions we usually let the error terminate the program because if a sync function throws in runtime it means something is wrong in my program, not in networkingThis is just the way you're choosing to see the problem. Promises can be used for anything, it's not tied to networking. I usually write promises that will be resolved when a modal window closes or when an application event happens.
It's just a simpler way to write code. The way you use it is up to you.
Also, async/await makes debugging a lot easier. The debugger can understand that the next expression after an "await" is supposed to be in the same function context. No more adding breakpoints to the callback function because only you know how the code is called at runtime. You debug async functions as normal functions.
while(!iterator.next().done)
I think you meant the above example and not the one you listed in the comment as generator objects in JS always return objects upon calling next method even after finish yielding for long and thus you could have an infinite loop on your hand here."F# to JavaScript with type providers
FunScript is a lightweight F# library that lets you rapidly develop single-page applications. You can connect to external data sources and call REST APIs with intellisense, produce dashboards using JavaScript visualization libraries and write asynchronous computations easily without explicit callbacks."
Functions that contain a try/catch cannot currently be optimized by V8. If we migrate to using try/catch rather than `.then/.catch`, I wonder if there's going to be any perf implications since previously optimizable functions may no longer be optimized.
socket.on("data", echo); // calls the echo function when data arrivesIt is really a relief when it comes to multiple AJAX/UI dependant logic eg.
if(await showDialog("get coffe ?") == "yes"){
results = await getCoffeFromServer();
}
else {
...
}Get the basics done right first imvho. I don't want developers staying late to try and understand why something isn't working in a MS browser anymore.
Seriously though. I think that argument is losing steam every time I do testing with Edge. It gets updated. It feels different.
Unless somebody were to tell me both IE and Edge belong to the same browser family, I wouldn't be and to tell.
I'd say it's fair to call it a new browser.
My point being: IE is just IE. Edge is Edge and we're happy about it.