-
Notifications
You must be signed in to change notification settings - Fork 106
Clarifying question: can await be used in top-level code? #9
Comments
Good question. There are three notions of "top-level code" that are interesting here; I think you are mostly asking about the REPL case (or, as in the case you linked, a hosted execution environment of same kind where the embedder can choose how to execute the user provided code). Here it should be mostly up to the host whether they want to allow (async function() {
// <embed user provided code here>
})(); For example like your link, this would likely work. However, it has two downsides. First, it hides all declarations inside the function scope, so there is no shared global across REPL inputs. Second, the return value is delivered asynchronously, so the embedding would have to decide how to handle that. The other two cases are the more formal ones that the language would have to decide on. For an ES6 <script>
var x = await userEnteredAValue();
function foo() { return x; }
var y = "hello";
</script>
<script>
console.log(y) // is this 'hello'?
console.log(foo()) // is this the value the user entered?
</script> There is already a In the ES6 Ultimately, I'm not sure it would make sense to add |
Thanks for the answer! From a user (and teacher) point of view, I like either the possibility that The reason is this: Pedagogically, it makes sense for the lesson on "input" to come before the If done with good top-level script support, async could make Javascript a David On Sat, Mar 29, 2014 at 12:29 PM, Luke Hoban notifications@github.comwrote:
|
Can you give an example of this? It's the first I've ever realized that scripts have a |
Since do-expressions are on the table for ES7, I wonder if it might make more sense to provide for this use case through an async version of do-expressions: // In a script (or even a module)
let result = do async {
await something;
} |
@getify - Good question. The HTML5 spec has dependencies on the So it may be that the web platform could get away with chaging the meaning of script tags to execute the script, if it returns a value, chain off that value (if its a promise, continue asynchonosly, else if its not, continue synchrnously). I actually cant' think of anything that would obviously break here. The biggest concern might just be the ability to "accidentally" slow down the load path. But in practice, that's something that is happening already in module loaders, so maybe not a critical concern. |
@zenparsing - Yes, that might be an option, but I expect that it wouldn't pass @davidbau's simplicity test. If you are willing to do that, it's not much of a stretch to go to: let result = (async function() {
await something;
})(); |
How exactly does a script "return a value"? You can't call |
Yes, that appears to be the case. See https://people.mozilla.org/~jorendorff/es6-draft.html#sec-runtime-semantics-script-evaluation. |
Interesting, I wonder if that's there for the |
@lukehoban I included the result capture for generality, but we'd leave it off for this use case: do async {
await whatever();
} Pretty simple, I think. And much cleaner that an IIAF. There will be no getting around sync/async duality in Javascript. The simple thing to do is to structure the language so that contexts are synchronous unless explicitly otherwise. |
for consistency, it would seem like... async do {
await whatever();
} ...would make more sense, no? |
So it may be that the web platform could get away with chaging the meaning (To help me understand - ) If the web platform did this, can you give a On Tue, Apr 8, 2014 at 9:23 PM, Kyle Simpson notifications@github.comwrote:
|
@davidbau Here's an example - note that it uses <script>
var x = await fetchAsync("www.bing.com");
</script>
<script>
document.write(x);
</script>
<img src="someimage.png"></img> This should result in the contents of bing.com followed by an tag. Normal script tags like these have to run to completion before DOM parsing and construction can continue. If you allow This is not unlike what has to happen when you have a |
Thank you for the example. It would behave the same way with a single This model would be terrific and simple, and it would give beginners a very David On Wed, Apr 9, 2014 at 6:38 PM, Luke Hoban notifications@github.com wrote:
|
Perhaps a related question is whether native promises have a done method. In promise libraries like Q, there is a done method with behaviour equivalent to:
Without this it's easy to miss error handling from your promise chain and have your async operations silently fail. If you were able to await at the top-level, the promise could simply be awaited and errors handled with try/catch, making this method redundant. If there was a way to do this an maintain backwards compatibility I think it would be a big win. I expect most people wouldn't want to do this in top-level code (as it would need to block the page from rendering). It would be more useful in event handlers IMO. Tom |
@tomyan In es6now we deal with this issue by introducing the concept of a "main" function. If that main function returns a promise (as an async function would) and if that promise ends up being rejected, then the error is propagated back to the user just like a synchronous error is. export async function main() {
throw new Error("oops");
} This approach seems to "just work" and keeps things separated and simple. Also, it's off-topic here but since you mentioned it, we are experimentally doing the same thing with event handlers: if the event handler returns a rejected promise, it gets propagated back to the user in the usual expected way. This seems to me to be the best way so far to deal with the |
@zenparsing sounds sensible, I'll give es6now a spin |
Summarizing where I think we are on this - there were three possible places we could deal with I suggest that we update the proposal to include the semantics for (3) as an extension of the async module loader, and that we include an informative note on (1) that REPL's should aim to support I think we should not try to address (2) in the current proposal. /cc @bterlson |
Speaking from the perspective of someone who teaches JS, I very much dislike that you would be creating yet another variation between normal JS and what the REPL does. Developers learn JS by trying things in REPLs (either CLI or in browser), and it's consistently confusing to them when they run across these various places where a REPL works differently from the global scope of a normal program. There are necessary differences, but we shouldn't be going out of our way to make more and more differences without really strong reason. I wrote at length about this frustration. In this case, I see no reason why we should encourage REPLs to diverge from the global script context. That is, if (2) isn't going to be handled, neither should (1). If (2) eventually gets handled in a later spec, like with |
REPLs should behave like modules, not scripts. |
This is getting off topic... It is not that easy. You want the following to work:
if each line is a Script it works but if each line is a Module it does not. |
Right, each line should not be a module, the entire REPL should be a module. Similarly, That said this is off topic indeed so I'll stop here. |
@getify - I don't know of any way for That leaves the question of whether you want to allow |
My objection was to including a note, and specifically to including a note (even a non-normative one) that says "should". If the spec doesn't aim to provide any guidance on how (for REPLs), then it shouldn't aim to provide any guidance on what (for REPLs) either. If a REPL wants to try it, having such a non-normative note in there isn't going to sway them one direction or the other. Despite the assertion "the entire REPL should be a module", that's not in any way reflective of any real world requirement (or even present/near-future reality). Some REPLs will, I'm sure, but others won't. One problem with making a REPL session a module is that modules don't have access to the global scope, and yet many developers do in fact use things like the dev console's "REPL" to interact with the global scope. Same goes with interactive debugging sessions. Also, if a REPL has an My only point is that it's in no way a foregone conclusion that all or even most REPLs will significantly differ from main scripts in terms of how they deal with top-level asynchrony (blocking, etc). Since this spec doesn't want to tackle that beast, it should remain silent on the topic altogether. |
This was discussed at the July TC39. Await at top level introduces a large number of complexities with the module loader - complexities that need to be worked out there before they can be considered here. As such, TC39 wants to see async functions without await at top level. Await will still be reserved so we can pursue this in later editions of 262. |
See greasemonkey#2275 (comment) And tc39/proposal-async-await#9 This is a bad idea for compatibility. Refs greasemonkey#2275
can't just the whole Top Level scope be marked async behind the scene? |
@pannous I believe part of the problem is that in Node.js, scripts must be loaded and evaluated synchronously (no async) - because I think it was discussed that, with ES6 modules, the top level scope could be marked async, because there is no "require function" - it's just a piece of syntax. But I haven't followed that discussion much, and I haven't taken much of a look at ES6 modules, so don't take my word for it! |
@towerofnix interesting and good point. But what about the 'Script' context, wouldn't an async default be reasonable there? |
Just to throw my hat in the ring - that this feature is blocked because of concerns about module loading is ridiculous. I don't care about the semantics of how const fetch = require('node-fetch')
const someval = await fetch('https://my.example/someurl.json')
// Use someval. Top-level await makes writing simple scripts like this 900% better, because I don't have to wrap all my code in a |
@josephg this repo is for the stage 4 proposal that landed in ES2017. You might be more interested in https://github.com/tc39/proposal-top-level-await ? |
Ah, thanks! |
In the proposal, it looks like "await" is to be used inside async functions.
Can "await" be used in top-level code?
The reason is, when teaching students, it makes a lot of sense to start with top-level code that does not contain function definitions, and it also makes sense to "await input", such as in this example using Iced CoffeeScript's "await". What would this example look like in this proposal?
http://pencilcode.net/edit/guessmynumber
The text was updated successfully, but these errors were encountered: