Allen Wirfs-Brock wrote:
On Jan 26, 2012, at 11:51 AM, Brendan Eich wrote:
We could say event handler attributes are scoped by the most-nested
scope -- the scope due to the last <script> element that was closed
before the element with the event handler attribute was processed.
This means generated scripts (document.write or DOM create* calls) do
not see the generating script's let and const bindings.
Why closed? All declarations within a /Program/ are instantiated
before evaluating any code in its <script> element so generated
scripts should be able to reference the bindings for those
declarations. However, if such reference are actually evaluated they
might fall into the bindings' temporal dead zones.
You're right, the entire outer <script> has been parsed and declarations
processed before anything runs. And the script element is appended to
the DOM too. It all works, except of course you can't tell what's
potentially shadowing anything!
But it's worse than that. What about <script async src="..."> (or the
HTML4-era, not fully supported on all browsers <scriptdefer
src="...">? Async scripts are not supposed to have global effects
other than defining functions that the page or app author ensures
won't be called till after all content (or at least all scripts, or
at least all of the needed async scripts) has finished loading.
Is this a specified restriction? If it is, I haven't been able to
find it anywhere.
No, this is underspecified and so inherently racy -- developers beware.
It's advisory but people use onload, DOMContentReady, or better
(http://www.whatwg.org/specs/web-apps/current-work/multipage/dom.html#current-document-readiness).
In what scope do async script let/const top-level bindings go?
If it is a specified restriction then I would think that when a
browser ES implementation actually processes such scripts they should
reject any top level declarations other than functions.
No, vars must be accepted too.
Regardless, it seems likely that indeterminate load ordering problems
created by HTML need to be solved at that level. Why don't script
elements have a dependency attribute:
Ok, are we really going to invent new <script> attributes or just solve
the let/const problem as it exists today? Adding attributes doesn't help
in the extant case.
<script src="someLib.js" type="application/javascript" async="async"
id="lib1"></script>
<script src="anotherLib.js" type="application/javascript"
async="async"id="lib2"></script>
<script src="baseApp.js" type="application/javascript" async="async"
id="base" after="lib1"></script>
<script src="extraApp" type="application/javascript" async="async"
after="lib2,base"></script>
Because that's brittle and slow -- you don't care about order, you
typically just want to race and exploit as much parallelism as possible,
given host CPU(s), the intervening network, TCP connection
sharing/limits/etc.
The situation is messy enough that I question the win of nesting
scopes. True, a global object subject to async-loaded effects is no
picnic, but it is the devil we know. And these var and function
bindings, however racy, are not supposed to be lexical, as let and
const are.
I think these are the alternatives we currently have under consideration:
SQ (status quo): every top level declaration are all implemented as
properties of the global object
STL (Single Top Level): All script blocks share a declarative
environment for new (not var and function) kinds of declarations that
shadows the global object. Scripts with duplicate declarations are
rejected.
TLpSi (Top Level per script, isolated): Each script block has a
declarative environment for new (not var and function) kinds of
declarations. Each shadows the global object but are invisible to
each other.
TLpSn (Top Level per script, nested): Each script block has a
declarative environment for new (not var and function) kinds of
declarations. Each is logically nest within and shadows the
previously processed script
STL is what I'm proposing.
I'm pretty sure the collisions-are-rejected thing is going to burn. It's
the opposite of what people not only abuse (unknown latent bugs), but
absolutely use and rely on today, with var and function among scripts.
I think that TLpSn corresponds to Andreas preference. One way to
look at TLpSn is that uses shadowing to accept the duplicate
declarations that STL rejects. This seems like a problem that is
better addressed by using modules. TLpBn
(s/B/S/ right?)
also raises issues like, what scope does an indirect eval use? I
haven't head anyone recently advocating for TLpSi. You can achieve
almost the same thing using SQ by wrapping a block around each script
body.
Right, although TLpSi is still attractive as a parallel to function
bodies, where we agreed body-level let has to bind in a body block that
shadows parameters and vars. Not much of a plus but it's a plausible
alternative.
In general, when I start think about the ways that lexical
declarations in separate scripts might interact I run into issue that
are probably best resolved using modules. I'm inclined to favor the
simpler solution and leave it to modules to deal with managing actual
interdependencies cases.
Is STL the simplest solution for users?
/be
_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss