Live data from Hacker News

Top-level await in JavaScript is a footgun

gist.github.com

91–100 of 115 posts

Re: Top-level await in JavaScript is a footgun

#91

Earlier quoted context omitted.

This is probably the bigger deal. It means that not only is top-level await dangerous , it's potentially destructive even when used correctly.

It's also based on yet further misunderstandings (in this case not understanding the ability of engines to do speculative fetches).

Can you elaborate at all?

I'm familiar with the concept, but I didn't think that it was standard practice or heading that way for JS. I also have the impression that it comes with serious overhead of its own, making the "await considered harmful" performance claims valid even in that case.

I don't mean that as an argument: if speculative fetches handle this issue I don't understand how, and I'd really like to know.

Re: Top-level await in JavaScript is a footgun

#92

Earlier quoted context omitted.

Domenic, I do wish you'd at least try to engage fruitfully in these discussions without resorting to your usual snark and condescension. When you talk about speculative fetches, are you suggesting that engines would guess at which modules were going to be imperatively imported before actually running the code? That doesn't seem like a general solution, or even a particularly desirable one, but I'm interested to learn…

And I wish you'd try to engage with me instead of jumping to your usual tone arguments. Yes, that is indeed what I am referring to, as engines already do for HTML.

When I tried to ask you about this stuff on Twitter the other day, this was your dismissive response: https://twitter.com/domenic/status/774762508091551745

Speculative fetching is possible in HTML because and and tags etc are declarative. Similarly, modules can be fetched without the code executing because `import` is declarative. How can a browser prefetch modules when it encounters an imperative statement like `x = await import(computedModuleId())` without actually running the code?

Re: Top-level await in JavaScript is a footgun

#93

Earlier quoted context omitted.

If you run an await as a first thing in the top-level, you have nothing in the event loop to run. Await blocks everything after itself, and that is very dangerous if done on the top-level.

In that script, yes. But in JavaScript you can have multiple scripts :)

> in JavaScript you can have multiple scripts

You mean, you can embed multiple script elements in HTML? Yes. But allowing global await in ES spec means also enabling it in node.

Re: Top-level await in JavaScript is a footgun

#94

Earlier quoted context omitted.

It's also based on yet further misunderstandings (in this case not understanding the ability of engines to do speculative fetches).

Can you elaborate at all? I'm familiar with the concept, but I didn't think that it was standard practice or heading that way for JS. I also have the impression that it comes with serious overhead of its own, making the "await considered harmful" performance claims valid even in that case. I don't mean that as an argument: if speculative fetches handle this issue I don't understand how, and I'd really like to know.

Speculative fetching is a time-honored technique in web browsers. During the tokenization phase of HTML, CSS, and even JavaScript, they speculatively start a fetch for a given URL, so that if the data needs to be evaluated later, it is ready to go without a network round-trip. (In HTML: script, link, img, video, etc. elements; in CSS: @import declarations; in script: certain common document.write('In the context being discussed here, it means that `await import('./foo.js')` could kick off a speculative fetch for foo.js and all of its dependencies during the tokenization stage---exactly the same as is done for declarative `import './foo.js'`. (Per spec, the fetch for `import './foo.js'` doesn't happen until parsing, which is generally too late to give a good user experience---i.e., this is something engines will already be doing.) You could even imagine extending this to `await fetch('./foo.json')`, although I imagine that will be more of a stretch.

Of course that doesn't help for dynamic cases like `` await import(`./language-packs/${navigator.language}.js`) ``. But that's exactly as you'd expect: if your application truly depends on runtime-determined resources before it can proceed, then of course it needs to avoid continuing to evaluate code that depends on those resources. Top-level await just gives you a way to express that dependency without wrapping the rest of your app in async functions.

Re: Top-level await in JavaScript is a footgun

#95

Earlier quoted context omitted.

And I wish you'd try to engage with me instead of jumping to your usual tone arguments. Yes, that is indeed what I am referring to, as engines already do for HTML.

When I tried to ask you about this stuff on Twitter the other day, this was your dismissive response: https://twitter.com/domenic/status/774762508091551745 Speculative fetching is possible in HTML because and and tags etc are declarative. Similarly, modules can be fetched without the code executing because `import` is declarative. How can a browser prefetch modules when it encounters an imperative statement like `x =…

Yes, I found all of your points wrong, as I'm explaining in a medium with more than 140 - @-names characters in this Hacker News thread.

See above for a response to your point here.

Re: Top-level await in JavaScript is a footgun

#96
post #80

Another misconception here is the lack of understanding of engines' speculative loading capabilities. It's very easy for an engine to notice `await import('./foo.js')` or even `await fetch('./foo.json')` during the tokenization phase, and realize it might be a good idea to go fetch that file (and in the former case, all of its dependencies). This is already done for HTML's tokenization phase (with img, iframe, etc.),…

but the use-case for these is not a static import (that is possible already), but a dynamic one, such as: await import(`${config.providerType}.js`); and this can't be resolved at tokenization phase (and brute-forcing it with speculative/symbolic execution would be too much of a hack IMHO).

Yes, indeed. If your app actually depends on dynamically-loaded information before it can continue, then of course your app needs to block further evaluation. Top-level await simply allows you to express that without placing the rest of your app inside async functions.

Re: Top-level await in JavaScript is a footgun

#97
post #78

Another misconception here is the lack of understanding of engines' speculative loading capabilities. It's very easy for an engine to notice `await import('./foo.js')` or even `await fetch('./foo.json')` during the tokenization phase, and realize it might be a good idea to go fetch that file (and in the former case, all of its dependencies). This is already done for HTML's tokenization phase (with img, iframe, etc.),…

But if the engine speculatively loads modules, doesn't that counteract the developer's intention to increase performance by loading a module only when needed? This is not a problem in HTML loading, because HTML doesn't have `if` statements.

It is a problem in HTML, actually, e.g. ``. Per spec that fetch should not happen until the div becomes un-hidden. (Which is only determinable at runtime, since you can override the UA stylesheet for div[hidden].) But browsers make the intelligent tradeoff that the image is likely to be used, by doing a low-priority fetch for foo.png.

Re: Top-level await in JavaScript is a footgun

#98
post #62

Earlier quoted context omitted.

But any module with a dependency on a module with top-level await will have to wait for that dependency. As will anything depending on that. It's not difficult to imagine some code nested deep in some NPM module completely changing the load behaviour of your app without you knowing.

Yes. Let's rephrase that first sentence. "Any module with a dependency on data that it needs to execute will have to wait for that data before it executes." That's a good thing.

Is it a good thing for your entire app to be held up by any component that needs to load data? I'm sceptical.

Re: Top-level await in JavaScript is a footgun

#99
post #98

Earlier quoted context omitted.

Yes. Let's rephrase that first sentence. "Any module with a dependency on data that it needs to execute will have to wait for that data before it executes." That's a good thing.

Is it a good thing for your entire app to be held up by any component that needs to load data? I'm sceptical.

But your entire app wouldn't be held up! Only that subgraph.

Re: Top-level await in JavaScript is a footgun

#100

Another misconception here is the lack of understanding of engines' speculative loading capabilities. It's very easy for an engine to notice `await import('./foo.js')` or even `await fetch('./foo.json')` during the tokenization phase, and realize it might be a good idea to go fetch that file (and in the former case, all of its dependencies). This is already done for HTML's tokenization phase (with img, iframe, etc.),…

I understand why `await import('./foo.js')` works here, as import() is not a normal function.

But in the case of `await fetch('./foo.json')`, fetch is a global. What happens if my code overwrites window.fetch and redirects ./foo.json to ./bar.json? Won't the engine try to fetch foo.json (which might not exist) when it should wait for the code to execute?

Post reply on HN