News for hackers. Stuff that matters.
Re:V8 adds support for top-level await by megous on Tuesday September 24, 2019 @05:56PM (#21065048)
It's nice, I guess, but huge?

Instead of:

    async function main() {
       // code
    }
    main().catch(console.error);
I'll be maybe writing:

    try {
      // code
    } catch (ex) {
      console.error(ex);
    }
Hrm?
Re:V8 adds support for top-level await by Scooty on Tuesday September 24, 2019 @08:33PM (#21066331)
Top level await does more than remove a main function. If you import modules that use top level await, they will be resolved before the imports finish.

To me this is most important in node where it's not uncommon to do async operations during initialization. Currently you either have to export a promise or an async function.

Re:V8 adds support for top-level await by tiglionabbit on Tuesday September 24, 2019 @11:48PM (#21067428)
Do we really want slow imports though? If you have a bunch of modules with async setup functions, would you not be able to Promise.all() them?
Re:V8 adds support for top-level await by Rapzid on Wednesday September 25, 2019 @12:29AM (#21067608)
That kinda stuff is typically an antipattern in C#; an async static "factory method" would be used(I use this pattern myself in Typescript). But I guess JavaScript has odd stuff like code chunking so the importau be pulling remote code and etc.
Re:V8 adds support for top-level await by pandapower2 on Wednesday September 25, 2019 @12:15AM (#21067542)
Sure, in many situations, but I guess if you need to setup things have have dependencies (init A then init B then init C) this will help.
Re:V8 adds support for top-level await by dvlsg on Wednesday September 25, 2019 @12:27AM (#21067595)
How so? I'm not seeing the benefit over exporting A, B, and C as functions, and then putting them together in another spot (like a composite root for pure DI, or an IoC container, etc).

Is the argument for top-level await that you don't need the other spot? Because I feel like you still do - except now it's implicitly inside not only A, but likely B and C as well to some extent. And in a very inflexible way.

Re:V8 adds support for top-level await by sieabahlpark on Wednesday September 25, 2019 @12:33AM (#21067627)
No one should be asynchronously executing code on import? I'd rather my code call a function to kick it off.
Re:V8 adds support for top-level await by lewisl9029 on Wednesday September 25, 2019 @01:36AM (#21067933)
Please, this.

Synchronous effectful imports are already are the source of so much frustration, and now we're adding asynchronicity to it?

Just export a init function and let your users choose when/where to run your effectful initialization code, sync or async.

Re:V8 adds support for top-level await by stagas on Tuesday September 24, 2019 @11:42PM (#21067398)
Oh that's interesting if this is the case. So now a module export can contain an asynchronously initialized db handler for example?
Re:V8 adds support for top-level await by spankalee on Tuesday September 24, 2019 @11:58PM (#21067478)
Please don't do that though!
Re:V8 adds support for top-level await by TimTheTinker on Tuesday September 24, 2019 @07:09PM (#21065655)
For some use cases, the difference can be a little more dramatic.

    fetch(allResourcesUrl).then(async response => {
      let allResources = await response.json();
      let pageResource = await (await fetch(allResources.page1.url)).json();

      // set up page with pageResource
    });
can be replaced with

    {
      let allResources = await (await fetch(allResourcesUrl)).json());
      let pageResource = await (await fetch(allResources.page1.url)).json();

      //set up page with pageResource
    }
Note use of a top-level block instead of a function context to hide local variables.
Re:V8 adds support for top-level await by elyobo on Tuesday September 24, 2019 @07:12PM (#21065689)
What's with the `let` though?
Re:V8 adds support for top-level await by joshAg on Tuesday September 24, 2019 @07:27PM (#21065817)
let plus the curly bracket scoping means that the variables only exist within the curly brackets, and not the global state.
Re:V8 adds support for top-level await by aledalgrande on Tuesday September 24, 2019 @08:00PM (#21066092)
Maybe he meant why not const?
Re:V8 adds support for top-level await by spartanatreyu on Tuesday September 24, 2019 @08:14PM (#21066188)
You would use const, unless you wanted to reassign the variable later in the same scope.
Re:V8 adds support for top-level await by elyobo on Wednesday September 25, 2019 @02:24AM (#21068218)
Correct. Example doesn't show modification of the variables later, better to use const.
Re:V8 adds support for top-level await by earthboundkid on Tuesday September 24, 2019 @08:59PM (#21066491)
Const is a complete waste of time for non-primitive types. I defy anyone to show me a single bug in a popular program that could have been prevented by using const for a function local object. It can’t be done. There are bugs caused by mutatable state. There are bugs caused by reassigning globals. There has never been a bug caused by reassigning a function local variable while leaving it mutable.
Re:V8 adds support for top-level await by hombre_fatal on Tuesday September 24, 2019 @11:56PM (#21067468)
Using the more restrictive construct until you actually need additional features (like identifier rebinding) is just engineering 101.

I think the onus would be on you to prove that using a less restrictive concept is worthwhile because it saves you two keystrokes. That, in contrast, seems like the opposite of good engineering. Like using classes over structs because class is shorter to type.

The more I think about your post, the more absurd it becomes.

Re:V8 adds support for top-level await by TimTheTinker on Wednesday September 25, 2019 @12:52AM (#21067708)
I think it can be argued both ways. I've seen a large TypeScript codebase with a pre-commit hook that enforces use of const on all non-reassigned variables. With that being done everywhere, it made for easy reading - whether a variable was being reassigned or not effectively became annotated in its declaration.

On the other hand, there are some good reasons not to use use const everywhere we can. Paul Sweeney lists a few here: https://medium.com/@PepsRyuu/use-let-by-default-not-const-58...

I'm not sure where I land yet. Perhaps it's a decision to make separately for each codebase.

Re:V8 adds support for top-level await by elyobo on Wednesday September 25, 2019 @02:28AM (#21068237)
I don't think I'd call any of those reasons good; the main thrust of them is "const doesn't do everything, so don't let it do anything". If that line of reasoning is appealing, then one might as well continue using var.
Re:V8 adds support for top-level await by megous on Wednesday September 25, 2019 @09:37AM (#21070629)
The main benefit of let/const over var is that it's block scoped. The benefit of const over let is pretty much nothing, much. It only prevents some limited form of re-binding. You can still easily re-bind const variables from inside a function:

    const x = 1;
    (function() {
        const x = 2;
        console.log(x);
    })()
or from an argument:

    const x = 1;
    (function(x) {
        console.log(x);
    })(2)
So it has limited value in any code that uses closures.
Re:V8 adds support for top-level await by e12e on Wednesday September 25, 2019 @03:12PM (#21074214)
Shadowing isn't rebinding?

If you've declared const x = 1, then that will hold for your scope?

If you go into a separate scope... Well, then you're in a separate scope?

Re:V8 adds support for top-level await by elyobo on Wednesday September 25, 2019 @03:16PM (#21074255)
Neither of those rebind the `const x`, which will continue to hold the value it was given.
Re:V8 adds support for top-level await by root_axis on Wednesday September 25, 2019 @04:18AM (#21068823)
The const keyword has absolutely nothing to do with state mutability, that is a misconception. const in es6 is a keyword meant to explicitly prohibit identifier reassignment and it does indeed reduce bugs because it communicates developer intention regarding how a variable reference is expected to behave in a section of code. Further, use of const by default is a best practice because it leaves less room for error in cases where a reassignment must never occur and increases readability by convention of the let keyword signaling that a reference will behave in a volatile way in proximal logic.
Re:V8 adds support for top-level await by earthboundkid on Wednesday September 25, 2019 @09:58PM (#21077457)
My whole argument was premised on const not having anything to do with mutability.
Re:V8 adds support for top-level await by aledalgrande on Tuesday September 24, 2019 @11:38PM (#21067379)
By waste of time do you mean performance or coding time? I feel like writing a character more is not a waste of time, if you are just following the convention that anything that is not going to be muted should be signed explicitly. It's not to prevent bugs, but for readability and ease of use.
Re:V8 adds support for top-level await by earthboundkid on Wednesday September 25, 2019 @09:59PM (#21077459)
Time deciding if you can/should rebind a variable or not is a waste of developer time.
Re:V8 adds support for top-level await by jhomedall on Thursday September 26, 2019 @12:17PM (#21082467)
You will know ahead of time whether you're going to be rebinding a variable. The use of const is a hint to the next person reading your code, since they won't be privy to your thought process.

In an ideal world, const would be the default, and you would have to opt into non-const.

Re:V8 adds support for top-level await by aledalgrande on Wednesday September 25, 2019 @10:56PM (#21077727)
Then when you will have to change or debug the same code instead of writing new, you will have to spend more time understanding what variable is the source of a state change, for example inside a loop. That is more of a waste of time to me.
Re:V8 adds support for top-level await by elyobo on Wednesday September 25, 2019 @10:25PM (#21077592)
I sort of agree; I solve this by never using let and never rebinding :) No need to think about it at all.
Re:V8 adds support for top-level await by earthboundkid on Thursday September 26, 2019 @09:19AM (#21080631)
Then you end up playing this game of jumping through hoops to omit variables. It's a tempting waste of time because it feels productive.
Re:V8 adds support for top-level await by elyobo on Saturday October 05, 2019 @02:29AM (#21164131)
Strangely it turns out that rebinding variables is a really uncommon need, so there's pretty much zero game playing.
Re:V8 adds support for top-level await by elyobo on Wednesday September 25, 2019 @02:30AM (#21068249)
> There are bugs caused by mutatable state.

> There has never been a bug caused by reassigning a function local variable while leaving it mutable.

The latter _is_ mutable state. const doesn't prevent all mutations, but it does prevent some, while let prevents none. I'll take the limited protections of const (with awareness of its limitations; many examples of let are of confused devs trying to avoid making their objects immutable).

Re:V8 adds support for top-level await by megous on Wednesday September 25, 2019 @07:02AM (#21069517)
I'm with you. Though typing `if (a = 1) {}` happens to me sometimes, and const may catch this earlier. I don't use a linter anymore, but I suppose any serious linter would warn about assignement in a condition, anyway.
Re:V8 adds support for top-level await by elyobo on Wednesday September 25, 2019 @03:23PM (#21074328)
Why have you stopped using a linter?

The popular airbnb eslint rules[1] require the use of const where a variable is not reassigned, which I've occasionally found handy.

[1] https://github.com/airbnb/javascript#references--prefer-cons...

Re:V8 adds support for top-level await by Zarel on Tuesday September 24, 2019 @11:09PM (#21067229)
If all you're doing on catch is forwarding to `console.error`, you could just write:

    // code
Outputting errors to console is the default behavior.
Re:V8 adds support for top-level await by olalonde on Wednesday September 25, 2019 @01:10AM (#21067795)
There's an important difference: the process will crash if you don't catch the error.
Re:V8 adds support for top-level await by robert_tweed on Wednesday September 25, 2019 @06:07AM (#21069290)
While this is 100% correct, if the main function has returned then the process was going to end anyway (assuming there isn't additional code after the call to main). If there's a main loop, then the catch needs to be inside that loop, not outside of main.

The only difference it will make here is to suppress the default stack trace[1] and errorlevel returned to the shell. If you are writing in this kind of "scripting" style, you probably don't want to suppress errorlevels, so leaving out the catch is not only simpler, it is safer.

[1] You may get a stack trace with an Error object, but not the default one from the Node process.

Re:V8 adds support for top-level await by olalonde on Wednesday September 25, 2019 @07:20AM (#21069623)
> While this is 100% correct, if the main function has returned then the process was going to end anyway (assuming there isn't additional code after the call to main).

That's not necessarily the case (or maybe poorly worded), e.g.:

    async function main() {
      // code
      setInterval(() => console.log('hey'), 1000)
    }
    main()
In real life, it would probably be a HTTP server holding up the process. It's true that you likely want to crash hard if you have unhandled error during server initialization but I would still catch the error because Node.js will otherwise print a bunch of ugly "UnhandledPromiseRejectionWarning" messages. E.g.:

    main().catch(err => {
      console.error(err);
      process.exit(1);
    });
With top level async landing in v8, I guess Node.js will eventually stop printing those warning messages.
Re:V8 adds support for top-level await by robert_tweed on Wednesday September 25, 2019 @09:35AM (#21070610)
You raise an interesting point. If you are doing anything non-trivial, you should definitely be using a main loop and catching errors inside that loop. You really don't want to rely on the default behaviour of orphaned timers, because that can get interesting.

I did a quick test just to see how bad things might get if you were to rely on orphaned timers like this. The important thing to keep in mind is that each of those timers is effectively its own thread, which can throw errors and terminate itself. But if those are orphaned outside of a runloop that can handle those errors, they will not be caught by the catch outside of main (which only catches errors thrown in the "main thread"). Rather, they become top-level, uncaught exceptions, which also terminate the process.

Here's an example illustrating what happens:

    async function main() {
        setTimeout( () => console.log( 'Hello' ), 3000 );
        setTimeout( function() { throw new Error('error 1'); }, 1000 );
        setTimeout( function() { throw new Error('error 2'); }, 2000 );
        throw new Error('oops');
    }

    main().catch( x => console.error( x ) );
The result here is that `oops` is displayed (the caught error from the "main thread") and then `error 1` is displayed, but the process is then immediately terminated. Neither `error 2` nor `Hello` are displayed.

Note that I use the term "thread" loosely, in the "green thread" sense. Hopefully the meaning is clear.

Re:V8 adds support for top-level await by casret on Tuesday September 24, 2019 @06:12PM (#21065173)
One thing that has bitten me is when you are using vm.run* and friends, it's impossible to get a result of it if you need to use async calls. Hopefully this solves that case.

There is also the original use case that the original proposal of needing to do async calls when during module loading.

Re:V8 adds support for top-level await by mattwad on Tuesday September 24, 2019 @06:53PM (#21065519)
I think the boon here will be for scripts that run once. Say I just want to query a few tables. Now, I no longer need a `main()` wrapper:

  const result = await db.events.find();
  console.log(result);
That's my whole script
Re:V8 adds support for top-level await by james-mcelwain on Tuesday September 24, 2019 @06:53PM (#21065523)
Or my preferred (gross) version:

    void async function main() {
       // code
    }()
Re:V8 adds support for top-level await by elyobo on Tuesday September 24, 2019 @07:14PM (#21065704)
Mine all tend to look like

  (async () => {
    // code
  })().catch(console.error)
Re:V8 adds support for top-level await by jraph on Tuesday September 24, 2019 @07:16PM (#21065723)
Wow, I had completely forgotten the existence of void in JavaScript.

Why is it needed here? To force an expression without using the parentheses?

Edit: Yes, it seems so, and this usage with functions is explicitly documented there: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...

Re:V8 adds support for top-level await by ericlewis on Tuesday September 24, 2019 @10:31PM (#21067013)
Yep. Exactly why. Seems silly since it doesn’t really care for types in the first place.
Re:V8 adds support for top-level await by nailer on Tuesday September 24, 2019 @07:46PM (#21065981)
You forgot the IIFE