Re: [whatwg] Preloading and deferred loading of scripts and other resources

Thanks for writing this all up. A few questions/thoughts:

(1) Dependencies in this model seem to be strict execution dependencies.
It's possible some use cases might want to use dependencies to describe
loading priority.

As an example, imagine a Facebook page with 3 JS files:
Feed.js -- Needed to render the user's feed
Chat.js -- Displays the user's friends who are online
PhotoViewer.js -- When the user clicks a photo, this file creates a photo
viewer allowing the user to browse an album. Until the user clicks
something, this file isn't needed.

Roughly, the behavior we want here is: load Feed, then Chat, then
PhotoViewer. But if the user clicks a photo move PhotoViewer to the front
of the line.

How do I express the relative ordering of Feed vs Chat vs PhotoViewer? I
wouldn't want to use dependencies, because if PhotoViewer depended on Chat
then if I call .load() on PhotoViewer it will force Chat to be downloaded.

(2) Can inline scripts have needs? This seems like something potentially
useful (eg, you include a script tag for Google maps then you have an
inline script to create a map. You want the inline script to only execute
once maps is loaded)

(3) How does loading interact with the cache? For example, if I have a
<link load-policy="declare"> and the resource is in the browser's cache,
would the ready promise be fulfilled? This could be very useful for
applications -- sometimes there is functionality you are willing to execute
immediately if the resource is in the user's cache.


On Fri, Aug 22, 2014 at 5:44 PM, Ian Hickson <ian@hixie.ch> wrote:

>
> When I last looked at preloading scripts, it was pointed out to me that
> the Web Perf WG had some work ongoing in this space, so I decided to let
> them take care of it. However, nothing much seems to be happening there,
> and so I'm looking at this again. It's also been pointed out that limiting
> this to just scripts preloading maybe taking too narrow a view, and that
> we should also consider preloading and deferring loading of other
> resources, such as images, style sheets, and so forth.
>
> I will start by looking at use cases again, then go through some of the
> feedback on the last proposal I'd made in this space, and then make a new
> proposal intended to address the use cases and feedback.
>
> On Fri, 15 Aug 2014, Ben Maurer wrote:
> >
> > [Use-case F:] A website has a page where media is the primary content.
> > It would like to make sure that media is downloaded before JS [e.g.
> > flickr, youtube, facebook photos]
> >
> > [Use-case G:] A website knows there's a piece of Javascript code that
> > the user might need if they click on a part of the page. The developer
> > would like to have the user download it, but not at the expense of other
> > resources.
> >
> > [Use-case H:] A website is prefetching photos in a photo album and would
> > like to make sure these images are lower priority than images the user
> > is actually viewing.
>
> On Mon, 28 Jul 2014, Ben Maurer wrote:
> >
> > [Use-case I:] Facebook uses an automated pipeline to decide what CSS/JS
> > files to package together. If we could pass a custom header in the
> > request for a CSS file (for example: what part of the page caused that
> > file to be loaded) we could use this information in our packaging system
> > to make smarter decisions.
>
> On Tue, 22 Jul 2014, Ben Maurer wrote:
> >
> > [Use-case J:] The way we render pages at Facebook [is essentially that
> > we] flush sections of HTML with a list of CSS and JS dependencies for
> > each section. The HTML is only rendered once these resources are loaded.
>
> > [Use-case K:] We have a few other use cases for this type of dependency
> > (for example, we have a method where you can say "call this callback
> > once resources X, Y and Z are requested").
>
> On Tue, 3 Sep 2013, Ryosuke Niwa wrote:
> >
> > [Use-case L:] A web page wants to load and execute a script widget.js if
> > the script is already cached in the browser.  However, it wants to load
> > other essential assets such as images first if it's not already in the
> > cache except as long as the user had not started interacting with the
> > parts of the page that require widget.js.
>
> On Tue, 18 Mar 2014, Jonas Sicking wrote:
> >
> > [Use-case M:] Being able to specify that an image/video should only be
> > downloaded "on demand" (aka "lazily"), i.e. when it's in view, or about
> > to be in view. Use case is both to lower bandwidth in cases of long
> > pages where the user doesn't always scroll to the bottom, as well as
> > make sure to fill the network pipe with the most important resources
> > first.
>
> > [Use-case N:] Being able to specify that a stylesheet should not block
> > rendering. Use case is to preload stylesheets that will be used by
> > content that isn't rendered in the initial view, but that might be
> > rendered later.
>
> > [Use-case O:] Being able to specify some form of prioritization for
> > resources like (non-blocking) stylesheets, (non-blocking) <script>s,
> > images, video, iframes etc. Use case is making sure to fill the network
> > pipe with the most important resources first. Possibly a simple
> > prioritization like "needed for initial rendering/not needed for initial
> > rendering" is enough, possibly there are needs for more finegrained
> > prioritization like "needed for initial rendering/needed for page
> > feature X that is commonly used, needed for other".
>
> On Fri, 30 Aug 2013, Yoav Weiss wrote:
> >
> > [Use-case P:] download dynamic page components (e.g. maps) only on
> > larger devices.
>
> On Wed, 10 Jul 2013, Kyle Simpson wrote:
> >
> > [Use-case Q:] I am dynamically loading one of those social widgets that,
> > upon load, automatically scans a page and renders social buttons. I need
> > to be able to preload that script so it's ready to execute, but decide
> > when I want it to run against the page. I don't want to wait for true
> > on-demand loading, like when my user clicks a button, because of the
> > loading delay that will be visible to the user, so I want to pre-load
> > that script and have it waiting, ready at a moment's notice to say "it's
> > ok to execute, do it now! now! now!".
>
> > [Use-case S:] One CMS plugin wants to load "A.js" and "B.js", where B
> > relies on A. Both need to load in parallel (for performance), but A must
> > execute before B executes. I don't control A and B, so changing them is
> > not an option. This CMS plugin [wants] to wait for some
> > user-interaction, such as a button click, before executing the code. We
> > don't want there to be any big network-loading delay visible to the user
> > between their click of the button and the running of that plugin's code.
> >
> > Another CMS plugin on this same page wants to load "A.js", "C.js", and
> > "D.js". This plugin doesn't know or care that the other plugin also
> > requests "A.js". It doesn't know if there is a script element in the
> > page requesting it or not, and it doesn't want to looking for it. It
> > just wants to ask for A as a pre-requisite to C and D. But C and D have
> > no dependency on each other, only a shared dependency on A. C and D
> > should be free to run ASAP (in whichever order), assuming that A has
> > already run [once] some user-interaction that initiates the load of A,
> > C, and D. This user interaction may be before the other plugin requested
> > A, or after it requested A.
> >
> > "A.js" can be requested relatively (via a <base> tag or just relative to
> > document root) or absolutely, or it might be requested with the
> > leading-// protocol-relative from, taking on whatever http or https
> > protocol the page has, whereas other references to it may specify the
> > prototcol.
> >
> > These plugins can't guarantee what ID's or classes they use are reliably
> > unique without undue processing burden.
>
> > [I've trimmed the text Kyle wrote here, but also implicit in his
> > description, as I understood it, was that A.js should only run once even
> > if both plugins tried to load it.]
>
> > [Use-case T:] I have two different calendar widgets. I want to pop one
> > of them up when a user clicks a button. The user may never click the
> > button, in which case I don't want the calendar widget to have ever
> > executed to render. [...]
> >
> > It'd be nice if both calendar widgets were built sensibly so that
> > loading the code didn't automatically render. One of them IS, the other
> > is unfortunately mis-behaving, and it will render itself as soon as its
> > code is run. [...]
> >
> > Furthermore, these two widgets are not "equal". Perhaps one is better
> > for smaller browser window sizes, and the other is better for larger
> > browser windows. [...]
> >
> > Regardless, the point is, there's run-time conditions which are going to
> > determine if I want to execute calendar widget A or B, or maybe I never
> > execute either. But I want them both preloaded and ready to go, just in
> > case, so that if the user DOES need one, it's free and ready to execute
> > with nearly no delay, instead of having to wait to request as I would
> > with only on-demand techniques.
>
> > [Use-case U:] I have a set of script "A.js", "B.js", and "C.js". B
> > relies on A, and C relies on B. So they need to execute strictly in that
> > order. [Now], imagine they progressively render different parts of a
> > widget. [...] I only want to execute A, B and C once all 3 are preloaded
> > and ready to go. It's [...] about minimizing delays between them, for
> > performance PERCEPTION.
> >
> > [For example, one of them might start playing a video, and another might
> > introduce the <canvas> slides for that video. You want all of the
> > relevant scripts to be run at once, so there's no point where the page
> > has a <video> element but doesn't have the <canvas>.]
>
> On Thu, 11 Jul 2013, Kyle Simpson wrote:
> >
> > [Use-case V:] you have a string of scripts ("A.js", "B.js", and "C.js")
> > loading which constitute a dependency chain. A must run before B, which
> > must run before C. However, if you detect an error in loading, you stop
> > the rest of the executions (and preferably loading too!), since clearly
> > dependencies will fail for further scripts, and the errors will just
> > unnecessarily clutter the developer console log making it harder to
> > debug.
>
> > [Use-case W:] some developers have even requested to be able to stop the
> > chain and prevent further executions if the script loads, but there's
> > some compile-time syntax error or run-time error that happens during the
> > execution. For them, it's not enough for B to simply finish loading
> > successfully, but that it must fully execute without error.
>
> On Sun, 14 Jul 2013, Kornel Lesiński wrote (trimmed):
> >
> > [Use-case X:] not all dependencies are JS files, e.g. authors use
> > plugins to load template files, JSON, images, etc.
> >
> > [Use-case Y:] not all dependencies are usefully satisfied immediately
> > after their JS file is loaded, e.g. some libraries may need asynchronous
> > initialization.
> >
> > [Use-case Z:] Another common kind of dependency scripts have is presence
> > of certain element in the DOM, e.g. `dropdown-menu.js` may require `<nav
> > id="menu">` to be in the document _and_ have its content fully parsed
> > before the script can run.
>
> On Tue, 27 Aug 2013, Ian Hickson wrote:
> >
> > Jake also mentioned these requirements:
> >
> > | - Provides an adoption path for browsers that don't support the new
> > |   feature (happy for the fallback to be blocking document-order
> > |   execution)
> > | - Is discoverable by pre-parsers (so async=false and old-IE's
> > |   readystate methods aren't enough)
> >
> > And Kyle mentioned this scenario that we need to handle as well (not
> > strictly a use case, more a variant on the above use cases):
> >
> > > I want to preload a script which is hosted somewhere that I don't
> > > control caching headers, and to my dismay, I discover that they are
> > > serving the script with incorrect/busted/missing caching headers.
>
> > Incidentally, I don't think the use case is or should be "make it
> > possible to write a performant script loading library". I think the use
> > case should be more like "make it unnecessary to ever write a script
> > loading library".
>
>
>
> Bearing those use cases and requirements in mind, here's the feedback
> received since the last proposal:
>
> On Thu, 29 Aug 2013, Jake Archibald wrote:
> > On 27 August 2013 22:55, Ian Hickson <ian@hixie.ch> wrote:
> > > On Tue, 9 Jul 2013, Bruno Racineux wrote:
> > > >
> > > > I would also strongly favor restoring the previous spec portion of
> > > > 'defer' which allow to have defer on inline script blocks (i.e. if
> > > > the src attribute is not present). I don't know why this html4
> > > > functionality was removed from html5?
> > >
> > > Well, primarily because basically nobody implemented it, but also,
> > > because it's not clear what the point is. Why would you need it?
> >
> > I like my scripts to be inert, as in have no impact on the page (like
> > jquery). I use a small inline script to start the work needed for that
> > page, meaning I know the starting point for all JS interacting with the
> > page is somewhere in an inline script. This is much easier to maintain
> > than scripts that trigger themselves ondomready depending on what they
> > see in the DOM.
>
> I agree entirely. But how does this impact defer=""? If the script has no
> effect, it really don't matter when it's run.
>
> Or are you saying you want an inline script to be deferred, so that it
> runs after all the external deferred scripts?
>
> Given legacy implementations and back-compat needs I doubt we could do
> this with defer="" at this point, but:
>
> > In your proposal, does this work?…
> >
> > <script src="whatever.js" whenneeded></script>
> > ...
> > <script needs="whatever.js">
> >    activateTheAlmightyWebsockets();
> > </script>
>
> Yeah, we should support that, certainly.
>
>
> > > On Wed, 10 Jul 2013, Jake Archibald wrote:
> > > >
> > > > If "dependencies" took a CSS selector it could be:
> > > >
> > > > <script dependencies=".cms-core" src="cmd-plugin.js"></script>
> > > >
> > > > Now the number of scripts with class "cms-core" can change between
> > > > versions of the CMS but the plugin still waits for them all. No ID
> > > > generation needed.
> > >
> > > Using a selector is an interesting idea.
> > >
> > > It makes it harder to detect and prevent loops, but not fatally so.
> >
> > I'm not sure it's possible to get into loops with this. I imagined
> > dependency resolution to happen once, on element creation or adding to
> > document (whichever happens latest). So with:
> >
> > <script src="a.js" needs="script[src=b.js]"></script>
> > <script src="b.js" needs="script[src=a.js]"></script>
> >
> > …the first script would have zero dependencies, because the selector
> > matches zero elements. The second would depend on the first, so the
> > execution order is a.js, b.js. The thing I like about the selector thing
> > is you can very easily get (almost) async=false behaviour:
> >
> > <script src="a.js" needs="script"></script>
> > <script src="b.js" needs="script"></script>
> > <script src="c.js" needs="script"></script>
>
> Ah. A one-off selector matching seems less interesting.
>
> With real-time matching, you could do things like:
>
>    <script src="fancytextarea.js" needs="textarea"></script>
>
> ...and have it get invoked once a textarea appeared, or some such. It
> would depend on exactly how the semantics were set up, I guess.
>
>
> > execute() should return a promise that resolves when the script
> > successfully downloads and executes.
>
> I guess we could do that. It's not clear to me what the benefit is. None
> of the use cases particularly seem to need it.
>
>
> > Also, should there be an event on the script element when the script has
> > downloaded, but not executed (like IE used to have)?
>
> Similarly here. What's the use case?
>
>
> > >   <script> elements also get a new needs="" attribute, which takes a
> list
> > >   of URLs. A <script> won't run (even if you call execute()) until all
> the
> > >   <script src=""> elements referenced by its needs="" attribute are
> > >   themselves ready to run. For example:
> > >
> > >      <script src="bbbbb.js" needs="aaaaa.js"></script>
> > >      <script src="aaaaa.js" async></script>
> > >
> >
> > It seems weird to refer to "needs" by url, but still require script
> > elements for those needs, I'd rather use IDs (or selectors yey!).
>
> IDs require more markup to do the same thing:
>
>       <script src="bbbbb.js" needs="a"></script>
>       <script src="aaaaa.js" id="a" async></script>
>
> Selectors require more markup or more complex selectors:
>
>       <script src="bbbbb.js" needs="#a"></script>
>       <script src="aaaaa.js" id="a" async></script>
>
>       <script src="bbbbb.js" needs="script[src='aaaaa.js']"></script>
>       <script src="aaaaa.js" async></script>
>
> Not clear to me that either are a win.
>
> Using URLs has the big advantage that it means you can do this logic
> across import documents, too, which will become more interesting when Web
> components are used more.
>
> Having said that, IDs and Selectors do have a few of advantages that
> aren't obvious in the above code: they let you reference elements other
> than scripts, and they avoid one confusing aspect of URLs which is that
> people interpret the following as actually executing a.js even if there's
> no <script> that mentions a.js in its src="":
>
>   <script src="b.js" needs="a.js"></script>
>
> Also, IDs mean you can have dependencies on local script blocks.
>
> One _disadvantage_ of IDs, though, is that they don't let us dedupe
> multiple scripts with the same URL as easily. Though maybe the solution
> there is for there to be some attribute (e.g. whenneeded="") that applies
> a new rule: if this <script> refers to a resource already mentioned by
> another <script>, then ignore this <script>, or make references to this
> <script> defer to the previous one.
>
> Then again, for scripts, maybe we can just tell people to use modules?
>
> One thing worth bearing in mind is that if we use a different syntax for
> "import" in ES6 modules than for needs="" (or whatever we call it) in
> HTML, then you won't be able to simply promote "import" to the attribute,
> you'll have to manually figure out what it means.
>
>
> > Also, I'm not sure we need to deal with the case above, where the script
> > with the dependency appears in the DOM prior to the script it depends
> > on. Avoiding this avoids the circular dependency problem (see my
> > selector example above)
>
> Circular dependencies are relatively easy to break.
>
> Not having requirements on order means that you can import multiple
> documents that each invoke script, and not have to worry about getting the
> order exactly right.
>
>
> > Does a script with "needs" but not "async" block rendering? I hope not.
>
> needs="" in this proposal implies async-ish behaviour. We want to move
> away from anything that blocks.
>
>
> On Thu, 29 Aug 2013, Glenn Maynard wrote:
> > >
> > > <script whenneeded="jit"> is a special mode where instead of running
> > > once the script's dependencies are met, it additionally waits until
> > > all the scripts that depend on _it_ are ready to run. ("Just in time"
> > > execution.) (The default is whenneeded=asap, "as soon as possible"
> > > execution.)
> >
> > This mode seems to be specifically for [use case U.]
> >
> > This one seems uncommon, and less like a dependency use case than the
> > others.  How often is this wanted?  Is it too inconvenient to just mark
> > them all @whenneeded, and say something like:
> >
> > document.querySelector("#C").execute(function() {
> >     A.render();
> >     B.render();
> >     C.render();
> > });
> >
> > That does require the modules render in a function, and not when the
> > script is first executed.  I don't know how much of a burden that is for
> > this case.
>
> If the scripts were able to expose an API like this, much of the work
> we're doing here would be somewhat trivial. My impression is that we're
> primarily talking about scripts from multiple third-party vendors that
> aren't designed to interact together. There's an example in the use case
> description, of a script that shows a video and a separate script that
> shows slides synchronised with the video, where one inserts a <video> and
> the other a <canvas>, and you want both to happen together so that you
> never have one without the other.
>
> (For a similar reason, I think it's probably not sufficient to just
> provide JS modules as the solution to all these use cases. While modules
> will certainly eventually become widespread, it will be many years before
> all the libraries someone might want to use are in module form. The module
> loader API allows authors to write scripts that work around this to some
> extent, but that's probably above the skill level for many authors, who
> just want to be able to include a script that was written by someone else,
> and follow some copy/paste instructions for hooking the script up to the
> relevant parts of their page.)
>
>
> > Alternatively, if an event is fired when a script's dependencies have
> > been met, then you could mark all three scripts @whenneeded, and call
> > (#C).execute() once C's dependencies have been met.
>
> I don't understand how this would work. Wouldn't this execute the
> dependencies before C got loaded? The idea here is to download everything
> first, then run it all at once.
>
>
> > Will a @defer dependency effectively defer all scripts that depend on
> > it?
>
> I think, as proposed, it would. However, that's somewhat moot; if you have
> a needs="" attribute you're going to be loaded async regardless.
>
>
> On Fri, 30 Aug 2013, Ryosuke Niwa wrote:
> > >
> > > <script> gets a pair of methods, incDependencies() and
> > > decDependencies(), that increase and decrease the dependency count by
> > > one, respectively decDependencies() throws if called when the count is
> > > zero. If decDependencies() is called and it reduces the number to
> > > zero,
> >
> > I strongly oppose to adding incDependencies/decDependencies.  We try not
> > to add those pairwise functions as much as possible our C++ code because
> > it's really hard to always pair function calls.
>
> On Thu, 29 Aug 2013, Glenn Maynard wrote:
> >
> > incDependencies() and decDependencies() may be hard to debug, since if
> > somebody messes up the counter, it's hard to tell whose fault it is.  A
> > named interface could help with this: script.addDependency("thing"); /*
> > script.dependencies is now ["thing"] */
> > script.removeDependency("thing");
>
> That's better than a count, true. Jake Archibald suggested using promises
> -- the API could accept a promise, and should then delay until all the
> promises are resolved. Using promises like that is probably the easiest to
> not screw up.
>
>
> On Fri, 30 Aug 2013, Glenn Maynard wrote:
> >
> > I don't like the name "jit", because it already has a different meaning
> > when talking about scripting.  If this was for CSS or WebVTT or
> > something else other than scripts, it wouldn't be as bad...
>
> Seems reasonable.
>
>
> On Tue, 3 Sep 2013, Ryosuke Niwa wrote:
> >
> > [...] in order for a dependency specified in "needs" to be satisfied,
> > "src" content attribute of the dependent script needs to match the value
> > when the script finished running. e.g. myscript.src = null leaves any
> > dependency on myscript unsatisfied.
>
> That seems reasonable. It would be a way to signal a load failure. I'm not
> sure how compatible it would be with the ES6 loader though. Once you're
> executing code, you're pretty locked-in in terms of what the dependencies
> are. We could maybe just consider the dependency to have failed if a
> script throws while being evaluated, though. That would match how it works
> for new ES6 module scripts.
>
>
> > Also make "needs" IDL property take in any HTML element; e.g. adding an
> > image element to "needs" makes the script wait until the corresponding
> > image resource is loaded.
>
> Good idea. In fact, rather than passing just an element, it seems even
> more powerful to be able to pass a promise, and to have elements that have
> a pending load to have a .loaded attributes that returns a promise. This
> would then integrate with Jake's idea of using promises to replace the
> dependency API mentioned above. The only problem is that it cuts off the
> UA from notifying the source of the promise that the resource is going to
> be needed, in the cases where we're delaying resources until needed.
>
>
> On Wed, 2 Oct 2013, Bruno Racineux wrote:
> >
> > I agree on the verbosity with the double markup. It feels redundant. But
> > perhaps so is the repeat of the script name with 'needs="A.js"' for
> > every script that would need a dependency.
>
> Well, presumably we need _some_ markup to indicate what a script depends
> on. I don't really know what else it would look like that would be less
> verbose than just giving the URL. We _could_ put this information in the
> script itself, as in modules, but then you have to fetch the file to know
> which file to fetch next, which wouldn't address all the use cases.
>
>
> > But if recompiling or looking up script+chars pairs are much slower than
> > deserializing a compiled representation of an entire scripts, it might
> > be worth considering down the road...
>
> Well, again, nothing is stopping browsers from doing this today.
>
>
> > >> I would also strongly favor restoring the previous spec portion of
> > >> 'defer' which allow to have defer on inline script blocks (i.e. if
> > >> the src attribute is not present).
> >
> > [...because] many inline functions have no need to run before
> > 'interactive' fires. A delay or 'promise' at this stage is too early and
> > rarely makes sense. Currently most common domReady hooks rely on
> > DOMContentLoaded. As such I see no very good reason to run such plugin
> > code prior to DOMContentLoaded.
> >
> > e.g I want to defer jQuery and I want my small inline script events
> > (based on the context of a page) parsed and run post jQuery, right after
> > DOMContentLoaded fires. That priority level is something that cannot be
> > done right now.
>
> Would it be sufficient to have the inline script depend on the jQuery
> script using needs=""?
>
>
> > Also something that makes me cringe, is the verbose repeat of long paths
> > (just like srcset does)
>
> Well we either have to repeat something, or do it from script.
>
> I toyed above with using IDs or selectors, and it's at least as bad as
> paths, IMHO. The main disadvantage of URLs is that it only lets us do
> scripts. I discuss this more after the feedback, below.
>
> From script, there's basically two approaches that make sense, I think. We
> could add dependencies using promises, and we could have some elements
> expose an interface of sorts specifically for this purpose. The advantage
> of the latter is that it would let the browser support "whenneeded"
> semantics, loading images and style sheets only when a script needs them.
>
>
> > If you need dependencies, then how about something shorter like a
> > dependency Index, with a 'preload' semantic on top of the
> > lazyload+postpone proposal, like:
> >
> > <script src="jquery.js" preload branch="A1">
> > <script src="plugin1.js" preload branch="A2">
> >
> > <script src="plugin2.js" preload branch="A2">
> >
> > <script>
> >       E('plugin2.js');
> > </script>
> >
> > i.e. The browser would takes the letter as indicator of a dependency
> > tree branch, and follow along it's priority number to determine the
> > dependencies to load when-needed. Or perhaps using the id attribute with
> > the letter+number syntax form.
>
> That seems rather convoluted. It's also hard to use this kind of scheme
> when multiple authors are sharing a page without knowing about each other
> (e.g. when you import two unrelated libraries).
>
>
> > My worry with [the concept of 'dependency' attributes and relying or
> > asking to the browser to handle it through markup], is a performance
> > caveat and potential increasing bloat in pages, vs properly isolating
> > what's needed on a per page basis. Platform like wordpress or drupal, or
> > poorly written plugins in any platform, already too often add scripts
> > globally to all pages, making pages an increasing piece of FUBAR script
> > bloat. With the 'whenneeded' concept, it can become quite tempting to
> > put many many scripts in the DOM without any guilt, or any sensible
> > notion of wether it's actually needed or not for a particular page.
>
> Fundamentally, any system that allows authors to load things on demand is
> going to enable this kind of behaviour. I don't think we should let that
> stop us from providing it. The cost of a few imports that don't get
> fetched isn't going to have that substantial an effect.
>
>
> On Thu, 29 Aug 2013, Brian Kardell wrote:
> >
> > "@slicknet: @Hixie @paul_irish this proposal conflates preloading with
> > dependency management. I would ignore the latter (as I did originally)."
> >
> > "@paul_irish: @slicknet @Hixie I feel similarly. Adding HTML semantics
> > for dep mgmt duplicates the work of AMD/CJS and ES6 modules.
> > #writingemailishard :)"
> >
> > "@_JamesMGreene: @paul_irish @slicknet @Hixie Agreed, adding script
> > dependency management in HTML would be complicated, messy, and verbose."
> >
> > Me: what they said.
>
> Well, the idea is not to add something redundant with JS modules; the idea
> is to very much integrate with JS modules. However, JS modules alone don't
> solve many of the use cases described at the top of this e-mail. It's no
> more complicated, messy, and verbose to have HTML support these use cases
> natively than it would be to require that authors write scripts to support
> them, IMHO (indeed I'd say it's a lot less messy). Do you think we should
> just not support some of the use cases in the list above?
>
>
> On Thu, 29 Aug 2013, Nicholas Zakas wrote:
> >
> > When Kyle and I originally started pushing for a way to preload
> > JavaScript many moons ago, the intent was very simple: to allow the
> > downloading of JavaScript and execution of JavaScript to be separate.
> > The idea being that you should be able to preload scripts that you'll
> > need later without incurring the cost of parsing and execution at that
> > point in time. There are many examples of people doing this, the most
> > famous being the Gmail mobile approach of loading JavaScript in comments
> > and then pulling that code out and eval()ing it.
> >
> > I still feel very strongly that this pattern is a necessary evolution of
> > how we should be able to load scripts into web pages. I just want a flag
> > that says "don't execute this now" and a method to say "okay, execute
> > this now". Allowing that flag to be set both in HTML and JavaScript is
> > ideal.
>
> This is what "whenneeded" and "execute()" provide, in the proposal from
> earlier in this thread.
>
>
> > The question of dependency management is, in my mind, a separate issue
> > and one that doesn't belong in this layer of the web platform. HTML
> > isn't the right spot for a dependency tree to be defined for scripts (or
> > anything else). To me, that is a problem to be solved within the
> > ECMAScript world much the way CSS has @import available from within CSS
> > code.
>
> What about dependencies on resources that aren't scripts?
>
>
> > I think the use cases other than the initial one (preload/execute later)
> > are best relegated to script loaders and are very tied to a current way
> > of thinking about loading JavaScript.
>
> Surely our goal should be to make script loaders unnecessary.
>
>
> > I'd rather provide a simple, low-level piece of functionality that make
> > the job of script loaders easier by providing a reliable API and then
> > let the dependency management use cases be addressed outside of HTML.
>
> Can you elaborate on why?
>
> It seems like having the browser be able to manage the dependencies across
> scripts and other resources, and manage the loading of those resources,
> would let the browser much better manage the network. There's no way for
> an author-provided script loader or other resource manager to know when
> other tabs are done loading critical resources so that non-critical
> resources can be preloaded, for example.
>
>
> > Other random thoughts:
> >
> > * "whenneeded" is a very strange name for that attribute. It doesn't
> > really tell me anything, as opposed to "preload", "noexecute", or
> > "future". How do I know when it will be needed?
>
> Yeah, whenneeded="" is a poor name. What we really need is a way to give
> the element's load policy -- should it precache or not, should it load
> asap or be deferred... For some elements, like scripts or style sheets, we
> might also want to provide the author control over whether the element
> should block subsequent scripts or be asynchronously loaded and applied.
>
>
> On Thu, 29 Aug 2013, Ryosuke Niwa wrote:
> >
> > To put it another way, I don't see why anyone wants to load a script and
> > not execute it other than for the purpose of avoiding the network
> > request at a later time.  However, if that were the main purpose of
> > providing such a functionality, then we also need to address the issue
> > of this load request needing to have a lower priority than other load
> > requests that are vital for the page.  In fact, we might want to avoid
> > sending the request of a script file altogether if the user isn't going
> > to interact the parts of the page that needs such a script.
>
> Right. That's what many of the use cases described above are about, which
> is how a dependency scheme ended up being part of the proposal in the
> first place.
>
>
> On Wed, 4 Sep 2013, William Chan (陈智昌) wrote:
> >
> > * <link rel=subresource> is great for resource discovery. Given the
> > above observation, note that it has some deficiencies. Most obviously,
> > it does not indicate the resource type. Browsers today can heuristically
> > assign a priority based on the resource type (script/image/stylesheet/
> > etc). Arguably, browsers could just use the filename extension as a hint
> > to the resource type, and that'd get us most of the way there. In any
> > case, Chromium, when it encounters <link rel=subresource> is going to
> > assign the resource load the lowest priority level, and only when the
> > parser encounters the actual resource via a <script> tag or something,
> > will another resource load be issued with the "appropriate" priority.
> > Almost all modern browsers will hold back low priority resource loads
> > before first paint in order to get critical scripts and stylesheets in
> > <head> ASAP without contention. Anything marked with <link
> > rel=subresource> will be considered low priority and in all likelihood
> > not requested early. Note that HTTP/2 currently does not support
> > re-prioritization (and that feature is being debated), so that means
> > that when the resource load for <link rel=subresource> gets issued over
> > an HTTP/2 connection, it will have the lowest priority, which is
> > probably undesirable. FWIW, I think <link rel=subresource> was a good
> > initial start, but suffers from key weaknesses and should be thrown out
> > and replaced.
>
> It seems pretty clear that in general it's better to provide the resource
> using its proper form -- be that <img>, <link rel=stylesheet>, <link
> rel=icon>, <script>, whatever -- and annotate it with attributes saying
> how to load it -- asap, later, when needed, whatever -- than it is to just
> generically say "also, I might eventually perchance refer to this URL".
> The former would allow the browser to also preparse the contents, e.g.
> decoding an image, parsing a style sheet or script, preparsing an HTML
> file, and the like.
>
>
> > * Given current browser heuristics for resource prioritization based on
> > resource type, all <script> resources will have the same priority.
> > Within HTTP/1.X, that means you'll get some amount of parallelization
> > based on the connection per host limit and what origins the script
> > resources are hosted, and then get FIFO. New additions like lazyload
> > attributes (and perhaps leveraging the defer attribute) may affect this.
> > With HTTP/2, there is a very high (effectively infinite) parallelization
> > limit. With prioritization, there's no contention across priority
> > levels. But since script resources today generally all have the same
> > priority, they will all contend and most naive servers are going to
> > round robin the response bytes, which is the worst thing you could do
> > with script resources, since current JS VMs do not incrementally process
> > script resources, but process them as a whole. So round-robining all the
> > response bytes will just push out start time of JS processing for all
> > scripts, which is rather terrible.
>
> I'm not sure what to do about this exactly.
>
>
> > * Obviously, given what I've said above, some level of hinting of
> > prioritization/dependency amongst scripts/resources within the web
> > platform would be useful to the networking layer since the networking
> > layer can much more effectively prioritize resources and thus mitigate
> > network contention. If finer grained priority/dependency information
> > isn't provided in the web platform, my browser's networking stack is
> > likely going to have to, even with HTTP/2, do HTTP/1.X style contention
> > mitigation by restricting parallelization within a priority level. Which
> > is a shame since web developers probably think that with HTTP/2, they
> > can have as many fine grained resources as they want.
>
> It's hard to come up with a super fine-grained model that works well with
> multiple competing scripts, but we can do better than what we have now,
> certainly. It seems we can at least split things into the following
> categories, in order of highest priority to lowest:
>
>    1. resources that are needed and are causing something to block
>        e.g. <script src="foo.js"></script>
>    2. resources that are needed and are neither blocking anything nor
>       explicitly deferred
>        e.g. <img src="foo.png" ...>
>    3. resources that are needed but are deferred
>        e.g. <script src="foo.js defer></script>
>    4. resources that the browser wants
>        e.g. <link rel=icon>, <html manifest>
>    5. resources that are not yet needed but which the author wants
>       precached when possible, and which have not been marked deferred
>        e.g. <link rel=subresource href=...>
>    6. other resources
>
> Is that fine-grained enough?
>
> We could add other levels too. Maybe a "defer" variant of #5, for
> instance:
>
>    <script src="foo.js" whenneeded precache defer></script>
>
> ...or some such. Or maybe put these things in a "load policy" attribute,
> as mentioned above.
>
>
> On Tue, 3 Sep 2013, Ryosuke Niwa wrote:
> >
> > Use case: A web page wants to load and execute a script widget.js if the
> > script is already cached in the browser.  However, it wants to load
> > other essential assets such as images first if it's not already in the
> > cache except as long as the user had not started interacting with the
> > parts of the page that require widget.js.
> >
> > i.e. it (loads and) executes the script immediately when and only when
> > the script had already been cached or the user had started interacting
> > with the parts of the page that requires the script.  Otherwise, the
> > script is loaded with a low priority.
>
> (I've added this one to the list above as use-case L.)
>
> This seems reasonable. It's kind of opportunistic loading -- it's saying
> execute this ASAP, but load it when needed, albeit with precaching if
> that is necessary.
>
>
> On Thu, 23 Jan 2014, Bruno Racineux wrote:
> >
> > What bugs me the most is that a developer's expectations is superseded
> > by a feature (the preloader) with different implementation per browser
> > engine, that are neither documented (in plain English) nor specced out
> > by W3C or WHATWG standards.
>
> Well the spec is just "parse the document and fetch the URLs you find",
> basically. It's a reasonably simple model. The implementation is a bit
> more subtle due to off-the-main-thread parsing, document.write(), and so
> on, but that shouldn't affect authors all that much.
>
>
> > The lack of such resource control can be a huge waste of bandwidth in
> > collateral damage along the benefits of the pre-loader. And in the case
> > of responsive images, it prevents us from implementing any simple
> > straight forward js solutions.
>
> I don't know about "straight-forward", but it shouldn't stop you from
> making scripted solutions in general. What you can't do from JS is poke
> content into the preloader before the script runs, which is what the
> preloader is basically for. (This is why the proposal earlier in this
> thread includes a dependency model: it lets you provide that information
> to the browser before script actually runs, so that the browser can do
> useful things with the information it has earlier.)
>
>
> > Anyway, to come to the point of this new parallel thread, this leads me
> to
> > a suggestion:
> >
> > 'HIDDEN' as [resources control]:
> >
> > Could 'resource control' be an associated spec of the 'hidden' attribute?
> > The semantics seem compatible with the specs implied by 'hidden'?
> >
> > Being that: hidden "Specifies that the element represents an element that
> > is not yet, or is no longer, relevant" [1]. That suggest it may not be
> > needed at all and if so, why load it's associated resources?
>
> It would certainly make sense for a browser to defer such a load. I don't
> know that it would make sense to not load it at all, though. However, it
> would make sense to provide controls for that.
>
>
> On Fri, 24 Jan 2014, David Newton wrote:
> >
> > In addition to overloading `hidden`, it misses the `postpone` use case
> > of images that we want to be visible (i.e. not have a `hidden`
> > attribute), but not loaded until/unless the user scrolls enough for them
> > to be within the viewport.
>
> Yeah. One thing we could do to make that work would be to have images do
> something similar to "whenneeded", where instead of an execute() method to
> indicate that they are needed, they trigger that state when the browser
> would otherwise try to render them.
>
>
> On Sun, 26 Jan 2014, Qebui Nehebkau wrote:
> >
> > Basically, - and I'm trying not to over-elaborate here, since my opinion
> > isn't really very important - I just mean that I don't think there
> > should be any guarantees about how (or whether) browsers will preload,
> > nor any specific means of controlling this, because the way resources
> > get loaded is not really any of the author's business. I also think that
> > the purely presentational choice of a specific image file to represent
> > the same content (and, even in the art direction case, they're clearly
> > the same content if they can be represented with the same alt text;
> > otherwise, there should be multiple img tags) should be specified in
> > CSS, not HTML; the argument that preloaders can't consider CSS isn't
> > compelling to me, because a browser's choice to preload an image or not
> > isn't important enough (or, I think it shouldn't be) to justify
> > entrenching in a specification.
>
> I think this makes sense, insofar as the UA should have the final say (not
> the author) regarding how things are downloaded. But on the other hand,
> the UA can do a better job if the author is able to provide hints to the
> UA about what the best order might be.
>
>
> On Wed, 12 Mar 2014, Jake Archibald wrote:
> >
> > One of the problems with async scripting is doing something when/if it's
> > ready. A complete solution looks like this
> > https://gist.github.com/jakearchibald/7662e012462c7537a075, it would be
> > a lot easier if we could just do:
> >
> > thing.loaded().then(function() {
> >   console.log('loaded');
> > }, function() {
> >   console.log('failed');
> > });
>
> Yeah, it would make sense for objects that have an eventual "ready" state
> to have an attribute that returns a promise for the current load state.
> That would fit in well with the model of adding dependencies by handing a
> promise over.
>
>
> On Wed, 12 Mar 2014, Boris Zbarsky wrote:
> > On 3/12/14 7:23 AM, Jake Archibald wrote:
> > >
> > > If the element hasn't loaded or is loading, vend a promise that
> > > resolves/rejects on its load/error event. If the element has fired
> > > load/error and isn't loading due to a source change, vend a
> > > resolved/rejected promise.
> >
> > This seems fundamentally racy, no?
>
> If you're changing what your image is pointing to, then yeah. We could
> vend an ImageBitmap object on the promise, I guess, if that's likely to be
> a problem. But in practice I don't see why it would be. Who's going to be
> using the same image to load multiple images without waiting for one to be
> ready?
>
>
> On Wed, 12 Mar 2014, Boris Zbarsky wrote:
> >
> > I realize no one would write actual code like this; the real-life use
> case I'm
> > worried about would be more like this:
> >
> >   // img is already loaded sometimes
> >   // Would like to observe a new load
> >   var promise1 = img.loaded(); // oops! This will be pre-resolved if
> >                                // we were already loaded, but otherwise
> >                                // will resolve with the new load we're
> >                                // about to start.
> >   img.src = bar;
>
> promise1 would be rejected as soon as you set 'src' if it hadn't loaded
> yet. If it had loaded, it would resolve straight away. In the latter case,
> you might observe either the old image or the new one, there's no way to
> know for sure.
>
> This is certainly bug-prone and I'm sure people will get it wrong and
> it'll usually work but sometimes not, due to the race. However, it's a
> logic error -- you're always observing the first load, not the second. It
> will always resolve straight away, either aborting or succeeding based on
> whether the original load is aborted or had completed.
>
>
> On Wed, 12 Mar 2014, Domenic Denicola wrote:
> >
> > With promises you should only ask for the "loaded" promise *after*
> > setting `src`; anything you retrieve before that represents a previous
> > load. Except, I suppose, for the base-case of images with no src,
> > transitioning to having an src? Or are they considered to have e.g.
> > loaded `about:blank` already? I.e. what should this do?
> >
> > var img = document.createElement("img");
> > var promise1 = img.loaded();
> > img.src = "foo.png";
> > var promise2 = img.loaded();
>
> I think we should spec this case to reject promise1, since the image is
> not .complete. I definitely don't think we should say that promise1 waits
> for the src to be set.
>
>
> > // (4) or it could be rejected with an "InvalidStateError" saying you
> > // can't wait for the loading of a non-src'ed image.
>
> This would be a perfect case for a sync exception, rather than a rejected
> promise, IMHO. Throwing an exception synchronously would clearly indicate
> to the programmer that the code is Just Wrong.
>
>
> On Fri, 14 Mar 2014, Jake Archibald wrote:
> >
> > Problem: Initialising an app after a non-module script
> > Solution: https://gist.github.com/jakearchibald/000ab94ad9fa5cfe62a8
>
> This seems simpler:
>
>    <script src="/whatever.js" id=whatever async></script>
>    <script type=module needs="whatever">
>      import app from "myapp";
>      app.init()
>    </script>
>
> We would have to make sure, though, that needs="" blocked the execution of
> the script _after_ the script was parsed to pull out 'import' statements.
>
>
> > [Use-case Q:] Want to avoid executing a social-media script until the
> user
> > give some intent, although the script should be preloaded.
> > Solution: https://gist.github.com/jakearchibald/dd25f0f2cf47bf2ab93e
>
> This seems simpler:
>
>    <script id="socializor" src="http://myface.com/socializor.js"
> whenneeded></script>
>    <script>
>     document.ready.then(function () {
>       document.querySelector('.social-button').addEventListener('click',
> function(event) {
>         document.scripts.socializor.execute();
>         event.preventDefault();
>       });
>     });
>    </script>
>
>
> > [Use-case S:] One plugin wants to execute "A.js" and "B.js" in order
> > following an interaction. Another wants to load "A.js" then "C.js" &
> "D.js"
> > in either order. "A.js" should only execute once. Scripts aren't written
> as
> > modules and out of developer's control.
> > Solution: https://gist.github.com/jakearchibald/120309d88a8bf025e92e
>
> That's a lot longer than the original proposal's solution. Also it
> requires the plugins to know about each other. Also it uses markup. If we
> can use markup, then the solution becomes even simpler than the original
> proposal's solution, IMHO:
>
>    <script src="A.js" whenneeded></script>
>    <script id=B src="B.js" whenneeded needs="A.js"></script>
>    <script id=C src="C.js" whenneeded needs="A.js"></script>
>    <script id=D src="D.js" whenneeded needs="A.js"></script>
>
>    // CMS plugin 1
>    <script>
>      document.querySelector('.button').onclick = function(event) {
>        document.scripts.B.execute();
>      }
>    </script>
>
>    // CMS plugin 2
>    <script>
>      document.scripts.C.execute();
>      document.scripts.D.execute();
>    </script>
>
> This is dramatically simpler than the solution presented above.
>
>
> > [Use-case T:] Preload 2 scripts, execute one or the other on particular
> > interactions
> > Solution: Same as Q.
>
> Similar to Q, I guess, but presumably not identical. Q only has one
> script. Again, though, I don't really see why we'd want something as
> complicated as suggested in that gist, when we can just have two script
> elements and call "execute()" on the one we want.
>
> (I note here that actually my solutions to Q and T here and in my e-mail
> from last year actually make the mistake of not distinguishing scripts
> that should be preloaded from those that should not. We probably need an
> explicit way to control the load policy here, as mentioned earlier in
> this e-mail.)
>
>
> > [Use-case U:] "A.js", "B.js", "C.js" - load them in parallel, execute in
> > order, only execute when all have preloaded.
> > Solution: https://gist.github.com/jakearchibald/5898e3a4fce62579d75b
>
> At a glance I've no idea what this script is doing. I don't think we want
> to be requiring that authors follow this kind of convoluted code to do
> something as simple as use case U. Recall that with the whenneeded=jit
> proposal and with needs="" taking URLs, this was as simple as:
>
>    <script src="/a.js" whenneeded=jit></script>
>    <script src="/b.js" whenneeded=jit needs="/a.js"></script>
>    <script id=c src="/c.js" whenneeded=jit needs="/b.js"></script>
>    <script>
>      // when we need it...
>      document.scripts.c.execute();
>    </script>
>
>
> > [Use-case V:] As U, but don't need to wait for all before executing.
> > Stop executing if any script fails to load.
> > Solution: https://gist.github.com/jakearchibald/ea7583d50bf3b46395e0
>
> It's not at all clear to me how a random author is supposed to figure out
> the difference between your solution to U and to V. It seems like any
> solution we provide for this should be way more straight-forward.
>
> The solution using the "whenneeded" proposal is the same as for U but with
> the "=jit" bit removed. I think we should probably make this more clear,
> e.g. making it policy="precache late-execute" vs policy="precache
> early-execute" or some such, but that's a far cry from going all the way
> to requiring that authors reduce arrays of promises.
>
> (Though to be fair, the solution I proposed to V doesn't actually go as
> far as the use case asks for, since it doesn't abort later loads. I think
> I intended tho onerror function in that solution to manually go in and
> stop the loads, but I'm not sure what exactly one could do to do that,
> since they're trying to preload, at least. Maybe we should just require
> that UAs be clever enough to notice that if they have aborted execution of
> a particular dependency chain, they should abort the loads too if they
> have no reason to think the loads will be useful later.)
>
>
> > [Use-case W:] As W, but break on execution errors
> > Solution: https://gist.github.com/jakearchibald/1b12a0e5414a69d9350f
>
> That's WAY more complicated than the whenneeded="" proposed solution.
>
>
> > [Use-case X:] Loading non-js dependencies
> > Solution: Use XHR + preload for prescanner
>
> XHR makes it hard to hook into the prioritisation system, but yeah.
>
>
> > [Use-case Y:] Some libraries may need async initialization.
> > Solution: These libs should provide a ready promise.
>
> Agreed, though I would just have them hand that promise to the <script>
> element so that it hooks into the rest of the dependency system.
>
>
> > [Use-case Z:] Wait on existence of particular element before executing
> > script
> > Solution: Either put the <script> that handles script loading after the
> > element in question, or use mutation observers
>
> Yeah.
>
>
> On Sat, 15 Mar 2014, Jake Archibald wrote:
> >
> > It's everything we need but perhaps not everything we desire. Last time
> > we went round with script loading the proposal for high-level dependency
> > declaration got weighed down by use-cases that should have been left to
> > lower level primitives. These are the lower level bits, something higher
> > level is still possible.
>
> It's not clear to me that promises really are the right "low-level" bits
> here. I think we need something lower than those that lets the JS module
> system, the HTML Imports system, the <script needs> system, and any
> promise-based dependency system all interact in one coherent way.
>
>
> > For legacy-free project, modules + promises for non-script assets are
> > the answer.
>
> How do modules solve the problems discussed here of defining when things
> should preload, wait til they're needed, etc?
>
>
> On Fri, 14 Mar 2014, Kyle Simpson wrote:
> >
> > I'd also like to make the observation that putting <link
> > rel=preload>.loaded() together with <script>.loaded(), and indeed
> > needing a promise mechanism to wire it altogether, is a fair bit more
> > complicated than the initial proposals for script preloading use-cases
> > from the earlier threads over the last few years of this list.
> >
> > For one, we're talking about twice as many DOM elements. For another,
> > there's a seemingly implicit requirement that we have to get both ES6
> > promises and DOM promises to land for these suggested approaches to
> > work. I don't know if that's already a guarantee or if there are some
> > browsers which are possibly going to land DOM promises before ES6
> > promises? If so, ES6 promises become the long pole, which isn't ideal.
> >
> > Lastly, I'd observe that many of the arguments against the
> > original/previous script preloading proposals were heavily weighted
> > towards "we don't like script loaders, we want to make them obsolete, we
> > need simple enough (declarative markup) mechanisms for that stuff so as
> > to make script loaders pointless…"
> >
> > At one point the conversation shifted towards ServiceWorker as being
> > "the answer". When we explored the use cases, it was my impression there
> > was still a fair amount of non-trivial code logic to perform these
> > different loading cases with SW, which means for the general user to
> > take advantage of such use-cases, they're almost certainly going to need
> > some library to do it.
> >
> > I can't imagine most end-users writing the previously-suggested
> > ServiceWorker code, and I'm having a hard time believing that they'd
> > alternatively be writing this newly suggested promises-based loading
> > logic all over their pages. In either case, I think for many of the
> > use-cases to be handled, most general users will need to use some
> > script-loader lib.
> >
> > So, if this .loaded() DOM promises thing isn't the silver bullet that
> > gets us to "no script loader utopia", then I don't see why it's
> > demonstrably better than the simpler earlier proposals.
> >
> > Moreover, the earlier proposals relied on the browser having logic
> > built-in to handle stuff like "download in parallel, execute serially",
> > which made their interface (the surface area users needed to work with)
> > much less than either the Promises here or the ServiceWorker before.
> >
> > What you're implicitly suggesting with both sets of suggestions is,
> > let's make the user do the more complicated logic to wire things
> > together, instead of the browser doing it. Why?
> >
> > Why isn't putting preloading into existing <script> elements (whether
> > exposed by events or by promises) better than splitting it out into a
> > separate element (<link rel=preload>) and requiring a third mechanism
> > (promises) to wire them up?
>
> I have to agree with Kyle here.
>
>
> On Sat, 15 Mar 2014, Jake Archibald wrote:
> >
> > Yep, markup is important for preparsers. <module>/<script type="module">
> > & ES6 modules give us a solution for the future.
>
> I don't really understand how. Modules offer one small part of what we're
> talking about here, but not much more. They don't offer a way to declare
> the dependency tree before the files are fetched, there's not really a way
> to concatenate modules without putting them in some other file like a ZIP
> file or an HTML Import, there's no way to delay the load or execution of a
> module until it's needed as far as I can tell, there's no way for modules
> to be declared as dependent on other resources, etc. I think modules will
> be an important part of this solution, but I don't think they are, on
> their own, a complete solution to the use cases presented.
>
> Certainly without a lot of rather complicated code.
>
>
> On Tue, 22 Jul 2014, Ben Maurer wrote:
> > On Tue, Jul 22, 2014 at 10:26 AM, Ian Hickson <ian@hixie.ch> wrote:
> > > On Mon, 21 Jul 2014, Ben Maurer wrote:
> > > >
> > > > (1) Allowing the user to specify parameters to Fetch. For example, a
> > > > user could say:
> > > >
> > > > <script src="/my.js" params="{'headers':{'myheader':'value'}}"
> > > > id="myscript" />
> > > >
> > > > This would allow the user to make any type of request customization
> > > > that they could for a direct call to Fetch.
> > >
> > > I think this would make a lot of sense. It's similar to earlier
> > > suggestions for controlling "Referer" on a per-link basis, but more
> > > generic. The problem I had with the proposals for controlling Referer
> > > was that while there's an obvious way to do it for <script> and
> > > <link>, it quickly starts breaking down don't have a 1:1 mapping of
> > > URL to element. For example, how do you get the fetches of URLs in a
> > > style sheet? Or of the poster frame of a <video> element? Or
> > > EventSource objects? Should we just have different ways to set the
> > > options for each one?
> >
> > I guess the upshot of of doing this through fetch is that once we added
> > the ability to specify fetch metadata it would hopefully reduce the need
> > for future modification of all the different ways one could load an
> > object.
> > http://lists.w3.org/Archives/Public/public-webappsec/2014Jan/0129.html
> > suggests the idea of using fetch for stylesheet subresources in the
> > context of subresource integrity.
>
> Yeah. I think it makes sense to expose a Request object once one is
> underway, and a RequestInit object (probably in the form of a JSON-encoded
> content attribute?) to configure it, at least for the main resources.
>
> I'm not sure how to handle elements with multiple resources, e.g. <video
> poster> or the new <picture> stuff.
>
>
> > > > (3) Allowing the user to construct a script or stylesheet from a
> > > > fetch. Complex sites often want precise control over when scripts
> > > > and stylesheets are loaded and inserted into the DOM. For example,
> > > > today inserting a stylesheet blocks the execution of inline script
> > > > tags. Some sites may know that this dependency is not needed.
> > >
> > > This specific use case is something I'm already working on. My
> > > long-term plan is to integrate something like this with the HTML
> > > Imports dependency model and the ES Module dependency model so that we
> > > have a single model that can handle everything.
> >
> > This sounds interesting. The way we render pages at Facebook seems very
> > similar to what you are suggesting. We essentially flush sections of
> > HTML with a list of CSS and JS dependencies for each section. The HTML
> > is only rendered once these resources are loaded. In essence, it seems
> > like we're doing inline HTML imports. We have a few other use cases for
> > this type of dependency (for example, we have a method where you can say
> > "call this callback once resources X, Y and Z are requested".
>
> Presumably the callback part of this could be done using promises if we
> expose promises for everything that can load.
>
> (I've added the above, as well as some other use cases you listed, into
> the use case list at the top of this e-mail, as use cases I through K.)
>
>
> > > > var myfetch = window.fetch(...);
> > > > myfetch.then(function(resp) {
> > > >   document.body.appendChild(resp.body.asStyleSheet());
> > > > });
> > > >
> > > > By calling asStyleSheet, the user could preserve the devtools
> > > > experience that exists today while still having complete control
> > > > over the fetching of their content.
> > >
> > > We could do this too. It's mostly just a convenience method, right?
> >
> > One advantage of doing this is that if there is some use case a site has
> > that isn't met by the dependency model they can still manually separate
> > the fetch of an object from its insertion into the DOM. Giving the
> > author the freedom to manually separate the fetch of a resource from
> > it's use in the document gives them a powerful ability to experiment
> > with different approaches to resource loading. asStyleSheet/asScript
> > wouldn't merely be a helper method to construct a stylesheet from a
> > given string of text. For example, line numbers in developer tools (or
> > JS stack traces) as if they were loaded directly from the given URL. A
> > browser might decide to parse the JS/CSS in a background thread as soon
> > as the document was fetched (or cache a pre-parsed version of the file).
>
> If we provide a way to not apply the resource until it's "needed", doesn't
> that just take care of the above automatically? I'm not sure I understand
> precisely the use case here.
>
>
> > This model also might be beneficial for sites that were written prior to
> > the dependency model you are describing. For example, at Facebook we
> > already schedule JS/CSS loading ourselves. This API would allow us to do
> > things like fetch a CSS stylesheet without blocking inline script
> > execution that follows while making a minimal number of changes to the
> > site.
>
> Can't you do that already? I'm not really following what you need to do
> here that you can't already do.
>
>
> On Tue, 22 Jul 2014, Boris Zbarsky wrote:
> >
> > One issue worth considering here: there are various situations (CSP,
> > extension) in which a browser would like to know what sort of resource
> > is being loaded, or more precisely how it will be consumed, before
> > loading it.
>
> This argues strongly for either reusing the existing loading mechanisms
> for preloading, or at least for providing that context information in the
> preload request.
>
>
> On Tue, 22 Jul 2014, Ben Maurer wrote:
> >
> > To follow this up with a concrete suggestion:
> >
> > var myfetch = window.fetch('my.css', {'fetch-as': 'stylesheet'});
> > myfetch.then(function(resp) {
> >   document.body.appendChild(resp.body.asStyleSheet());
> > });
> >
> > You can only call asStyleShet if fetch-as=stylesheet. Passing this
> > parameter would cause the browser to do all the things it would do if it
> > were fetching a stylesheet. For example, it would specify an accept
> > header of text/css unless otherwise specified. It would request at the
> > same priority as the browser requests other stylesheets (again, unless
> > overridden with a yet-to-be-defined syntax). Rules around CORS and
> > tainting would be identical to a normal stylesheet fetch (namely that
> > you could call.asStyleSheet on a request to a different origin but it
> > would have whatever restrictions the browser has on stylesheets from
> > different origins). Links in the stylesheet would be interpreted
> > relative to the URL used to load it, etc.
> >
> > Essentially, fetch-as=stylesheet would be the canonical definition of
> > the browser's behavior around loading stylesheets. It would define the
> > behavior if the proposals I suggested in the original email were
> > implemented -- namely if the user chose to pass parameters to the fetch
> > algorithm or if the user accessed the result of a stylesheet's fetch.
> >
> > Boris, Will -- would this setup address the concerns you have about the
> > problems websites that use XHR to load resources encounter?
>
> How would this interact with th ES6 module loader? Would fetch() be above
> or below it?
>
>
> On Wed, 30 Jul 2014, Ben Maurer wrote:
> > On Wed, Jul 30, 2014 at 11:35 AM, Ian Hickson <ian@hixie.ch> wrote:
> > > On Wed, 30 Jul 2014, Anne van Kesteren wrote:
> > > >
> > > > it would be desirable to have Accept / Accept-Language be set by
> > > > APIs, such as <img>. XMLHttpRequest already does this (unless a
> > > > developer added those headers), see http://xhr.spec.whatwg.org/
> > > >
> > > > If we are eventually going to expose something like a "Fetch" object
> > > > for each API that can issue a fetch it would seem best if these
> > > > details were defined at the API-level.
> > > >
> > > > I guess for now I'll add some notes to the network-level bits of
> > > > Fetch to indicate Accept / Accept-Language cannot be set at that
> > > > point by the user agent.
> > >
> > > There's three ways that I see:
> > >
> > >  1. Expose it on a "fetch" object available from all the places that
> can
> > >     do fetches. (HTMLImageElement, XMLHttpRequest, StyleSheet, etc)
> > >
> > >        var img = new Image();
> > >        img.src = 'foo.png';
> > >        img.fetch.doWhateverWithTheAcceptHeader('foo');
> >
> > At what point is the fetch actually being initiated? It's possible that
> > fetch will offer some things which can be done post-request (eg,
> > dynamically changing the spdy priority), but the accept header may need
> > to be specified pre-request.
>
> The fetch wouldn't be initiated until the event loop spun, but other than
> that, it's hard to predict exactly when it'll be done in the general
> sense. Depends on things like the load policy.
>
>
> On Thu, 31 Jul 2014, Anne van Kesteren wrote:
> >
> > Probably not before the end of the current task. The only exception to
> > that is EventSource and maybe WebSocket, but they can have a constructor
> > argument of sorts to make this work I guess.
>
> WebSocket probably won't use fetch. Good point about EventSource though.
> If we want to add requestInit settings for that, please file a bug.
>
>
> On Thu, 7 Aug 2014, Ilya Grigorik wrote:
> >
> > Latest draft: https://igrigorik.github.io/resource-hints/
>
> The preconnect, preload, and prerender link types seem important to define
> in more detail, I'm glad you are doing this work. I suggest that for
> things like scheduling and prioritisation, we reuse the proposals that
> this thread end up at (whatever that is, be in the proposal below or
> something evolved from that).
>
> Are there requiirements and use cases that you need to address that aren't
> covered by the proposals in this e-mail? I think I covered them all, but
> I'm not 100% sure.
>
>
> On Fri, 8 Aug 2014, bizzbyster@gmail.com wrote:
> >
> > +1 to breaking the dependency between fetching the resource and how it
> > is later used in the document. This type of “late binding” enables many
> > page optimizations.
>
> Does anyone have a concrete depiction of this use case so we can evaluate
> the proposal in this thread againt the use case?
>
>
> On Mon, 11 Aug 2014, Ilya Grigorik wrote:
> >
> > Will this result in API that extends beyond import and ES6 module use
> > cases? For example, I want to have the building blocks that will allow
> > me to declare these dependencies on my own: "these two images before
> > that script, but after this stylesheet, oh and that stylesheet should
> > have higher priority than"... We can express all of this in HTTP/2, and
> > I'd like that to be surfaced to the developers as a first class API.
>
> That's my goal. I don't know if the ES modules spec will be extended
> sufficiently to support that, but I hope so. The alternative is that we
> have two mostly redundant dependency systems, which I assume wouldn't be
> popular with browser vendors.
>
>
> > I'm looking at the gliffy, but having a hard time understanding how this
> > will work... It's murky to me how I'd declare a resource, specify its
> > priority relative to others, and/or add a dependency. Any other (more
> > complete) examples, by any chance? :)
>
> Check out the examples at the bottom of this e-mail, let me know if they
> answer your question, let me know how they look!
>
>
> That concludes the feedback that was sent on the previous proposals.
>
> There's also some other developments that are relevant.
>
> There's JavaScript's modules, as mentioned earlier. Modules introduce
> their own dependency system. It would probably behoove us to integrate
> them with whatever we have for making scripts depend on images and so on.
>
> HTML Imports are also coming along, and they also have a dependency
> system. Again, we should probably make sure that this integrates with the
> JavaScript modules dependenc system and whatever we come up with to
> address the use cases listed earlier.
>
> There's a bug tracking the merging of the dependency systems:
>
>    https://www.w3.org/Bugs/Public/show_bug.cgi?id=25715
>
> I also brought this up in es-discuss recently, in a series of e-mails on
> the subject.
>
> Before we can come up with a coherent overarching model, though, we need
> to know what precisely it is we need to address the use cases in this
> e-mail. Let's first look at the dependency tree aspect.
>
> There's a variety of objects that one might want to depend on:
>
>  - JS modules
>  - <script> elements
>  - <img> elements
>  - <video> elements
>  - promises
>  - inline style sheets
>  - external style sheets
>  - HTML imports
>  - etc
>
> Some can be identified by ID, some by URL, some by element or object,
> others by some sort of name.
>
> They don't all need to be identifiable from an attribute. For example, I
> don't think we need to make it possible for a <script> to depend on a
> promise declaratively. It's ok if depending on a promise can only be done
> via an API call.
>
> Some of these are somewhat special. For example, if we want multiple
> <scripts> pointing to the same src="" to be deduped, then the dependency
> mechanism needs to be based on URLs in some way (and presumably
> pre-redirect URLs otherwise we make the dependency mechanism depend on
> network latency). HTML imports also probably have to be URL-based, because
> the actual Document object that an HTML import imports doesn't exist until
> the import has been started.
>
> Modules make this a little more complicated, in that there's a desire that
> modules be named so that you can e.g. import "jquery" and be safe in the
> knowledge that jQuery will be imported regardless of its local filename,
> assuming that it has been previously declared.
>
> In HTML imports, the mechanism to identify another HTML import to depend
> on is <link rel=import href="...">. This only gets invoked once the
> resource has already been fetched. HTML imports are identified by URL.
> That URL has to be deduped -- each master document only imports each
> URL once.
>
> In JS modules, there's syntax in the script itself, which works similarly.
> The syntax identifies modules using a string. The script is first parsed,
> the dependencies are identified, they are fetched, this happens
> recursively, and then the scripts are evaluated.
>
> CSS similarly has @imports, though those are currently _not_ deduped. We
> should probably change that, so that at least CSSRuleLists are deduped.
> Alternatively, we can have a feature that forces deduping (or vice versa).
>
> To avoid the latency of a round-trip per dependency level, it would be
> good if the dependencies could be predeclared, even for e.g. CSS or JS
> modules, where you would normally only mention the dependency when you
> import it.
>
> Some dependencies have a presence in the same document, or can have a
> presence without any particular difficulty. For example, <script src="">
> elements (not modules) all get listed in the document, even if they depend
> on each other. However, not all dependencies are this way. For example,
> ES6 modules can reference modules that aren't otherwise mentioned.
> Similarly, style sheets can @import other sheets, but if you <link
> rel=stylesheet> those sheets in the parent document, you're going to
> change the cascade in probably noticeable (page-breaking) ways.
>
> So if we have a way to declare dependencies declaratively in the markup,
> we have an interesting mixture of requirements, even if we assume that
> we're not going to be able to reference things like promises declaratively
> and can safely leave those to an API:
>
>  - being able to reference specific elements (e.g. depending on an inline
>    script or style block)
>
>  - being able to reference specific URLs in the context of specific
>    handling (e.g. "this URL is an ES6 module that someone will import", or
>    "this URL is a CSS file that someone will try to @import")
>
> This suggests either that the dependency mechanism needs to be able to
> take different types of identifiers (e.g. element IDs or selectors on the
> one hand, and URLs+contexts on the other), or that we need to have two
> ways to declarare dependencies, e.g. two attributes (one for IDs, one
> for URLs+contexts), or that we should rely on rel=preload/rel=subresource
> to handle the second type.
>
> Here's how these three options could look, assuming that bar.css is a CSS
> file that foo.css imports, and "baz" is the ID of an element that this
> style sheet depends on (maybe a <script> element).
>
> * different ways we could jam all this into one attribute:
>
>    <link rel=stylesheet href="foo.css" dependson="bar.css as css, baz">
>
>    <link rel=stylesheet href="foo.css" dependson="css:bar.css baz">
>
>    <link rel=stylesheet href="foo.css" dependson="bar.css css; #baz">
>
> * different ways we could have multiple attributes to split this
>   information out into:
>
>    <link rel=stylesheet href="foo.css"
>          dependson-id="baz" dependson-css="bar.css">
>
>    <link rel=stylesheet href="foo.css"
>          dependson="baz" dependson-href="bar.css as css">
>
> * using just IDs and rel=preload or rel=subresource:
>
>    <link rel=subresource type="text/css" href="bar.css" id="bar">
>    <link rel=stylesheet href="foo.css" dependson="bar baz">
>
>    <link rel=preload type="text/css" href="bar.css" id="bar">
>    <link rel=stylesheet href="foo.css" dependson="bar baz">
>
>    <link rel="preload stylesheet" href="bar.css" id="bar">
>    <link rel=stylesheet href="foo.css" dependson="bar baz">
>
> * reusing the existing mechanisms for each type, but having a way to force
>   a particular case not to be instantiated ever, because it will instead
>   be instantiated using the other mechanisms (e.g. @import):
>
>    <link declare rel=stylesheet href="bar.css" id="bar">
>    <link rel=stylesheet href="foo.css" dependson="bar baz">
>
> These all suffer from pretty notable disadvantages: complicated syntaxes
> in attributes or complicated multiple-attribute processing models for the
> first five cases, having to introduce a whole new way to declare that
> something is "CSS" for all but the last two, and lack of a decent
> backwards- compatibility story for the last two. The three before the last
> one also suffer from not having an obvious way to be extended to
> predeclare JS modules. The last one could be extended easily enough:
>
>    <script declare type=module id=jquery href="p/jq/main.js"></script>
>    <script type=module dependson=jquery>
>     import $ from "jquery";
>    </script>
>
> We could also introduce a new void element specifically for preloading:
>
>    <preload kind=stylesheet href="bar.css" id="bar">
>    <link rel=stylesheet href="foo.css" dependson="bar baz">
>
> ...where the "kind" is from a list of predefined types that browsers can
> preload, like "stylesheet", "module", "script", "image", etc. However,
> introducing a new void element is a non-trivial cost.
>
> Two other problems with the <link> examples above are the duplication of
> information because of using id="", and the use of type="", a MIME type,
> to identify the resource type, when in practice how to handle a feature
> depends on both more than the MIME type (e.g. script program vs ES6
> module) and less than the MIME type (e.g. most image/* types are handled
> by sniffing, not based on the type). The declare="" idea avoid this by
> reusing the existing mechanisms.
>
> Merging the <preload> and rel=preload/rel=subresource ideas, one could
> imagine a variant that used a different attribute rather than type=, so
> that we didn't have to give a MIME type.
>
>    <link rel=preload as=stylesheet href="bar.css" id="bar">
>    <link rel=stylesheet href="foo.css" dependson="bar baz">
>
> ...or:
>
>    <link rel=subresource kind=stylesheet href="bar.css" id="bar">
>    <link rel=stylesheet href="foo.css" dependson="bar baz">
>
> rel=subresource has the minor advantage of being already implemented in
> Chrome, at least. On the other hand, rel=preload is shorter and would let
> us use a shorter attribute name (as="" vs kind="" -- as="" doesn't read
> well when the link type is "subresource"). Also, "subresource" is much
> harder to type, at least for me. If we're left with deciding between
> rel=subresource, rel=preload, and declare="", then basically the choice
> becomes one of how important backwards-compatibility is: do we want
> something we can deploy today, something we can deploy next year, or
> something we can deploy next decade? The longer we can wait, the neater
> the solution. The sooner we want it, the more we have to compromise.
>
> The attribute dependson="" could probably also be refined. People have
> suggested various names that could work:
>
>    uses=""
>    needs=""
>    dependson=""
>    dependencies=""
>    subresources=""
>    import=""
>
> uses="", needs="", and dependson="" seem more or less equivalent. I'm a
> bit dubious about adding an attribute that ends with "on" to avoid the
> similarity with event handler attributes. dependencies="" and
> subresources="" seem a bit long without giving an obvious benefit.
> import="" seems reasonable, but I'm worried that it is too close to the
> ES6 "import", CSS "@import", or HTML rel="import", which all have similar
> but stronger semantics. Here we're not trying to actually effect an
> import, we're just trying to let the browser know that a particular
> element is going to come in useful when this element is invoked.
>
> There have also been some proposals with names that don't really fit
> grammatically, like depends="". I haven't considered those further.
>
> Let's take the above example and add more nodes to the dependency tree,
> and see how it looks with the various proposals.
>
> rel=preload, as=..., uses=... -- the shortest names mentioned above:
>
>    <!-- core files -->
>    <script src="core.js" type=module id="core"></script>
>    <link rel=preload as=stylesheet href="core.css" id="core-css">
>    <!-- calendar files -->
>    <link rel=prelaod as=stylesheet href="calendar.css" id="cal-css"
>        uses="core-css">
>    <link rel=preload as=image href="imgs/cal.png" id="cal-sprites">
>    <script src="calendar.js" type=module
>        uses="core cal-css cal-sprites"></script>
>
> rel=subresource, kind=... subresources=... -- has a nice consistent
> symmetry, but man is it annoying to type:
>
>    <!-- core files -->
>    <script src="core.js" type=module id="core"></script>
>    <link rel=subresource kind=stylesheet href="core.css" id="core-css">
>    <!-- calendar files -->
>    <link rel=subresource kind=stylesheet href="calendar.css" id="cal-css"
>        subresources="core-css">
>    <link rel=subresource kind=image href="imgs/cal.png" id="cal-sprites">
>    <script src="calendar.js" type=module
>        subresources="core cal-css cal-sprites"></script>
>
> rel=subresource, kind=..., needs=... -- less annoying, still annoying:
>
>    <!-- core files -->
>    <script src="core.js" type=module id="core"></script>
>    <link rel=subresource kind=stylesheet href="core.css" id="core-css">
>    <!-- calendar files -->
>    <link rel=subresource kind=stylesheet href="calendar.css" id="cal-css"
>        needs="core-css">
>    <link rel=subresource kind=image href="imgs/cal.png" id="cal-sprites">
>    <script src="calendar.js" type=module
>        needs="core cal-css cal-sprites"></script>
>
> rel=preload, kind=..., needs=... -- similar to as/uses:
>
>    <!-- core files -->
>    <script src="core.js" type=module id="core"></script>
>    <link rel=preload kind=stylesheet href="core.css" id="core-css">
>    <!-- calendar files -->
>    <link rel=preload kind=stylesheet href="calendar.css" id="cal-css"
>        needs="core-css">
>    <link rel=preload kind=image href="imgs/cal.png" id="cal-sprites">
>    <script src="calendar.js" type=module
>        needs="core cal-css cal-sprites"></script>
>
> declare="" and needs="", reusing the existing load mechanisms:
>
>    <!-- core files -->
>    <script src="core.js" type=module id="core"></script>
>    <link declare rel=stylesheet href="core.css" id="core-css">
>    <!-- calendar files -->
>    <link declare rel=stylesheet href="calendar.css" id="cal-css"
>        needs="core-css">
>    <img declare src="imgs/cal.png" id="cal-sprites">
>    <script src="calendar.js" type=module
>        needs="core cal-css cal-sprites"></script>
>
> We do use kind="" on <track>, for something similar, which would be an
> argument for kind="" over as="". Also, as="", while cute and, in context,
> pretty nice looking, does suffer from lack of clarity when used out of
> context (plus, consider the confusing with is="" from Web components).
> Searching [link element as attribute] is not likely to get you as helpful
> a set of results as [link element kind attribute]. It's really tempting to
> just use the declare="" attribute, though, since that reuses so much
> machinery and avoids having to intoduce kind="" at all.
>
> It's harder to decide between needs="" and uses="". I think "needs"
> probably has a slight edge only because it, to me at least, more strongly
> implies that if the load of a dependency fails, the element cannot be
> satisfied. uses="" sounds more opportunistic. For now, let's suppose we go
> with needs="".
>
> (As an aside, I should add that I welcome bike-shedding on all these
> names. If you have an idea I haven't considered, or a way of looking at
> the names that I haven't mentioned here, please don't hesitate to bring it
> up. Now's the time, before anything gets implemented.)
>
> The discussion above suggests that needs="", the attribute that defines
> these dependencies, should take a space-separate list of IDs, rather than
> URLs. This, though, brings in a new set of subtle questions. When are
> these IDs resolved? Should they update dynamically? For consistency with
> the rest of the platform, the answer should probably be yes, but this does
> introduce "spooky action-at-a-distance" effects, which is unfortunate. For
> example:
>
>    <link id=a rel=preload kind=image href="a.png">
>    <link id=b rel=preload kind=image href="b.png">
>    <script needs="a" ... id="demo">
>     ...
>    </script>
>    <!-- later... -->
>    <script>
>     document.getElementById('a').id = 'c';
>     document.getElementById('b').id = 'a';
>    </script>
>    <!-- later... -->
>    <script>
>     document.scripts.demo.execute();
>    </script>
>
> Which image(s) should be downloaded? If the browser is aggressively
> precaching everything that something depends on, probably all of them; if
> it's only fetching what is actually needed when it's needed, presumably
> only b.png. ES6 modules make this a bit more complicated too, in that we
> don't fully control when the normalize hook is run (which is where we'd
> presumably evaluate these mappings).
>
> In the example above, the <script> element has a "..." in its attribute
> list, which brings us to the next and more thorny part of the whole issue:
> how to tell the browser that certain resources are only to be loaded when
> they are needed.
>
> Normally, browsers aggressively download everything.
>
>    <link rel=stylesheet href="a.css">
>    <img src="a.png" alt="">
>    <script src="a.js"></script>
>
> All three files will be immediately fetched and applied. In fact, it's
> worse than that; the style sheet will block the script from executing, and
> the script will block the parser from continuing to the rest of the page
> (e.g. blocking a subsequent video from starting to play).
>
> We have ways to prevent the blocking for <script>, namely defer="" and
> async="". Their exact behaviour is a little subtle, but, broadly speaking,
> the defer="" attribute delays the script until after the page has finished
> loading, while the async="" attribute tries to run the script as fast as
> possible without blocking. Style sheets don't currently have such a
> mechanism, though it has previously been requested. Everything else, more
> or less, loads like the async="" behaviour. (All of the above, including
> 'defer', also delay the 'load' event.)
>
> So, to address most of the use cases described at the top of this e-mail,
> we need a way to delay the application (and in some cases loading) of
> resources until they are "needed", for some definition of needed.
>
> Some of the use cases also need a way for us to de-dupe references to the
> same resource, even across otherwise independent packages. For example,
> two separate packages that both want to load jQuery, or two separate style
> sheets for different parts of the app that both want to load a "reset"
> sheet first. (The CSS case is not spoken about as much as the scripting
> case, but it's still real, especially for big applications; see, for
> instance, this talk:
>
>    https://www.youtube.com/watch?v=_MD1WQclOJM
>
> ...about Google+'s rather elaborate system to solve this.)
>
> In the proposal from last year, I had suggested a whenneeded="" attribute
> with three states: today's status quo, a value to delay the load and
> execution until the script was needed (indicated by calling "execute()" on
> the script element), and a value to delay the load until then and delay
> the execution until everything depending on this script itself was also
> ready to execute.
>
> As discussed earlier in this e-mail, however, this is probably
> insufficient. We probably need to just expose a way to control the load
> policy for an element.
>
> There's actually two somewhat orthogonal aspects to this. When to download
> the resource, and when to execute or apply it. For some resources, when to
> download it is irrelevant (e.g. inline scripts), and for some, when to
> apply it is irrelevant (e.g. images).
>
> For downloading, it again breaks down into several somewhat orthogonal
> controls - when, and what priority:
>
>  - When to consider downloading it:
>     - don't wait, just get it immediately
>     - wait until either it's needed, or nothing that _is_ needed is
>       being downloaded (precaching)
>     - wait until it's needed, don't precache
>
>  - What priority to give the download:
>     - download it as soon as possible
>     - allow other downloads to take priority
>
> That sort of maps to three booleans:
>
>  - fetch-asap vs fetch-when-needed
>  - precache vs no-precache
>  - high-priority vs low-priority
>
> ...except that 'precache' requires 'fetch-when-needed'.
>
> You can alternatively view this as six states:
>
>  - download now at high priority (default)
>  - download when needed at high priority (fetch-when-needed)
>  - download when needed at high priority, but allow precaching
>    (fetch-when-needed, precache)
>  - download now at low priority (low-priority)
>  - download when needed at low priority (fetch-when-needed, low-priority)
>  - download when needed at low priority, but allow precaching
>    (fetch-when-needed, precache, low-priority)
>
> For execution/application, there's basically one control, with five
> levels (one of which is the equivalent of declare="", from earlier):
>
>  - execute this now, blocking subsequent scripts from executing until it
>    is done (this describes the legacy behaviour of <script> and style
>    sheets, and probably shouldn't be exposed. It also overrides the
>    download behaviour, since when you're blocked you need the resource as
>    soon as possible and so you won't wait, nor use a low-priority channel)
>
>  - execute as soon as possible after it is downloaded
>
>  - execute as soon as it is needed
>
>  - execute just before anything depending on this is executed
>
>  - don't ever execute this, this is a placeholder for something that will
>    be referenced from elsewhere that is just being listed here so that we
>    can preload it and reference it
>
> The "execute as soon as possible after it is downloaded" and "execute as
> soon as it is needed" options would obviously be equivalent when the
> download option is "when-needed", but it would _not_ be the same for other
> cases (e.g. it controls whether to execute after precaching or not, and
> decides when to apply inline resources, which don't get downloaded in the
> first place).
>
> Let's give those five states straw-man names: block, use-asap,
> use-when-needed, use-late, and declare.
>
> The "low-priority" modifier applies to most of these values, and
> "precache" applies to all those with fetch-when-needed. Expanding out all
> the combinations, using square brackets to show different possible
> combinations for the "low-priority" and "precache" values, we get:
>
>    block
>    use-asap [low-priority]
>    use-when-needed [low-priority]
>    use-late [low-priority]
>    declare [low-priority]
>    fetch-when-needed use-asap [low-priority] [precache]
>    fetch-when-needed use-when-needed [low-priority] [precache]
>    fetch-when-needed use-late [low-priority] [precache]
>    fetch-when-needed declare [low-priority] [precache]
>
> These names are quite confusing. In particular, "use-when-needed" alone
> makes it sound like it'll be fetched when needed too, not immediately. And
> "fetch-when-needed use-when-needed" is pretty horrible for what might be a
> pretty common case. (So common the earlier proposal just had a single
> attribute for it, whenneeded="".)
>
> Here's an alternative set of names for the same states. I used "async" for
> "use-asap" because that's basically what <script async> today does. The
> others are new names.
>
>    block
>    async [low-priority]
>    when-needed preload [low-priority]
>    late-run preload [low-priority]
>    declare preload [low-priority]
>    optimistic [low-priority] [precache]
>    when-needed [low-priority] [precache]
>    late-run [low-priority] [precache]
>    declare [low-priority] [precache]
>
> Here, "preload" means "fetch it ASAP", and "precache" means "fetch it
> whenever you want (but not later than when it's needed)". If you had one
> of each of these, what order would they load in, assuming all the ones
> that are marked as loading only when needed were requested after
> everything else had loaded, and that only one resource could be loaded at
> a time? It would be something like this, I think:
>
>    block
>    async
>    async low-priority
>    when-needed preload, declare preload
>    when-needed preload low-priority
>    late-run preload
>    late-run preload low-priority
>    optimistic precache
>    when-needed precache, declare precache
>    late-run precache
>    optimistic low-priority precache
>    when-needed low-priority precache
>    late-run low-priority precache
>    // (pause until they are marked as needed)
>    optimistic
>    when-needed, declare
>    late-run
>    optimistic low-priority
>    when-needed low-priority, declare low-priority
>    late-run low-priority
>
> (I'm assuming "when-needed" and "declare" have the same importance in
> terms of fetching priority.)
>
> Even when you hide the low-priority lines, it's still a lot:
>
>    block
>    async
>    when-needed preload, declare preload
>    late-run preload
>    optimistic precache
>    when-needed precache, declare precache
>    late-run precache
>    // (pause until they are marked as needed)
>    optimistic
>    when-needed, declare
>    late-run
>
> We clearly don't need all of these. In particular, we could merge
> "preload" and "precache" so that it's more than a hint, but less than an
> immediate request. This gets us down to basically four keywords plus
> "async" and "block", which represent the default behaviours for most
> interesting elements:
>
>    block
>    async
>    optimistic [precache] [low-priority]
>    when-needed [precache] [low-priority]
>    late-run [precache] [low-priority]
>    declare [precache] [low-priority]
>
> We could also add a flag that says "always force a new download, rather
> than deduping", to match current default behaviour of certain features.
> Say, "force".
>
> Here's how these would map to some existing features:
>
>    <link rel=stylesheet>: block force
>    <style>: block
>    @import: block force
>    <script src>: block force
>    <script src defer>: when-needed precache force; plus, the page load
>       itself triggers the script as being needed
>    <script src async>: async force
>    <link rel=icon>: when-needed precache
>    <img ...>: async force
>    <img ... hidden>: async low-priority force
>
> So for example, if you had a style sheet that you only wanted to apply
> when it was needed by some script, but which could be downloaded earlier
> if the browser wanted to, and which should be deduped if there are
> multiple instances of it loaded, you could declare it as:
>
>    <link rel=stylesheet href="foo.css"
>          load-policy="when-needed low-priority precache">
>
> For resources that don't have an "execute" step, like images, there's no
> concept of late execution. For these, optimistic, when-needed,
> and late-run are all essentially the same, and "block" doesn't apply; the
> choice is really between "fetch now", "fetch soon", and "fetch when
> needed", aka async, when-needed precache, and when-needed.
>
> Again, I'm not a great fan of these names. Bikeshed away.
>
>
> To complement the dependency model and load policy, we need a few
> additional features. There needs to be a way to indicate that something
> that is waiting to be needed is in fact needed (separate from something
> depending on it, that is). So probably a method like .execute(), though
> it would be nice to have a name that could apply to all elements.
>
> The browser also needs a way to say "I need this" for some elements, such
> as images -- there, it would kick in when the element is being rendered.
>
> It would also be nice to be able to have an API that lets you add elements
> to another element's dependency list without having to add an ID and add
> the element that way. (That would also allow cross-document dependencies,
> which might be useful.) Maybe foo.addDependency().
>
> To make this all work well with promises, it would also be nice to have an
> API to say "add this promise as a dependency". This could be an overload
> of the element-receiving one mentioned in the previous paragraph.
> Unfortunately, as far as I can tell, a promise breaks the back-channel
> logic. For example, consider this case:
>
>    <link rel=stylesheet href="foo.css" load-policy="when-needed" id=a>
>    <img src="bar.png" alt="..." load-policy="when-needed" id=b>
>    <script>
>      links.a.addDependency(images.b);
>    </script>
>
>
> At this point, ideally, nothing would happen. Now suppose that we told the
> style sheet link that it was needed. Ideally, the image would then
> download itself also. But in practice, I don't see how we can actually do
> that. There's no back-channel along the promise to inform the image that
> it should now start downloading itself.
>
> So I guess for promises as dependencies, we'd only have a way to wait on
> the promise, not a way to also trigger the load that the promise
> represents. That's probably sufficient for most cases if we also have a
> way to add a dependency by ID.
>
> To help hook into things that use promises, we should presumably have
> .loaded and .ready attributes that return promises for when something has
> executed/applied (.loaded, similar to onload) and when things are
> prefetched and ready to go (.ready). We could pair that last one with a
> new event, onready, for those who prefer the event model.
>
> We also need a way to actually say that things should be executed. For
> consistency with onload, I guess a .load() method.
>
>
>
> Earlier in this e-mail I mentioned ES6 modules and HTML imports, and
> pointed out that they both had dependency systems. If we add in the system
> described above for HTML resources, we now have three. I think it's pretty
> critical that we not require that browsers implement three redundant
> dependency systems.
>
> Since the more mature of the three is ES6, I've been trying to work on
> fitting HTML imports and the system described above into the ES6 module
> world. Mostly this just means defining the default behaviour of the ES6
> loader hooks, though there's probably a few things that would need
> changing at the ES6 module level to make it fully work (I've been sending
> this feedback to the es-discuss list directly for those who want to follow
> along over there).
>
> The main thing that ES6 doesn't currently support is the ability to set
> the dependencies ahead of time. The discussion below assumes that that
> will be resolved. There's also a minor issue with being able to associate
> metadata with a load when it's discovered as a dependency and when its
> name is normalised, so that @import rules can work right.
>
> Modulo those issues, the idea is that any fetch within the context of a
> Web page would be added to the ES6 module loader mechanism.
>
> The "normalize" hook would need a way to reference elements by ID. There's
> two obvious ways to do that: support any string that matches an ID as
> being an ID, and support any string starting with a "#" as being an ID.
> The former is neater-looking:
>
>    <link rel=stylesheet id=foo ... load-policy="when-needed">
>    <script type=module>
>      import styles from "foo";
>    </script>
>
> ...but means that we're now overloading the string passed to import as
> multiple things (package locators, IDs, and URLs) in a rather ambiguous
> way. So the hash idea is probably better:
>
>    <link rel=stylesheet id=foo ... load-policy="when-needed">
>    <script type=module>
>      import styles from "#foo";
>    </script>
>
> It's important to distinguish this from a URL, though; I don't expect this
> to work:
>
>    <!-- in foo.html -->
>    <link rel=stylesheet id=foo ... load-policy="when-needed">
>
>    <!-- in bar.html -->
>    <link rel=import href="foo.html">
>    <script type=module>
>      import styles from "foo.html#foo"; // the #foo here presumably has no
> effect?
>    </script>
>
> But what should the "#foo" do? Probably it should throw, but we could
> imagine maybe having the "normalize" hook wait until the import is done?
>
> ("normalize", by default, would probably also need to support two other
> things:
>   1. absolute and scheme-relative URLs
>   2. some sort of relative naming for ES6 modules themselves, so that
>      you can do things like:
>        import "jquery";
>        import "../base/utils";
>        import "login/login";
>      ...and have it get "jquery.js" from some predeclared registry,
>      "../base/utils.js" relative to the current script (not the doc!), and
>      "login/login.js" in the same way.
> I'm not really sure how to do the package part of this.)
>
> The other hooks do pretty much the obvious things, except maybe
> "instantiate" which has to figure out how to import something once it has
> its MIME type.
>
>
>
> Pulling all of the above together, here's the tentative proposal:
>
> These "loadable" elements:
>
>    <script>, <link>, <style>, <video>, <img>, <object>, <iframe>, <audio>
>
> ...get the following new attributes:
>
>    needs=""            Gives a list of IDs of other elements that this one
>                        needs, known as The Dependencies. Each dependency
>                        is added to this element's [[Dependencies]] in the
>                        ES6 loader.
>
>    load-policy=""      The load policy. Consists of a space-separated
>                        set of keywords, of which one may be from the
>                        following list: block, async, optimistic,
>                        when-needed, late-run, declare. The other
>                        allowed keywords are precache, low-priority,
>                        and force. (Maybe we disallow "block" and
>                        "force" since they're for legacy only.)
>                        Different elements have different defaults.
>                        "precache" isn't allowed if the keywords
>                        "block" or "async" are specified, since those
>                        always load immediately.
>
>    load-settings=""    A JSON-encoded dictionary to pass to the Request
>                        constructor.
>
> ...and API:
>
>    .addDependency()    Passed a promise, makes this element depend on that
>                        promise. Passed a "loadable" element, does the same
>                        as if that element's ID was mentioned in needs="".
>
>    .load()             Mark the element as needed, and apply or execute it
>                        as soon as possible. Returns the new .loaded
>                        promise (any earlier one is rejected).
>
>    .ready              Promise indicating calling load() will immediately
>                        apply or execute when load() is called.
>
>    .loaded             Promise indicating that the element has applied or
>                        executed.
>
>    .request            The current Request object, if a fetch has been
>                        started.
>
>    .needs              reflects needs, maybe as a custom object, or
>                        otherwise as a DOMTokenList
>
>    .loadPolicy         reflects load-policy, maybe as a custom object, or
>                        otherwise as a DOMTokenList
>
>    .loadSettings       reflects load-settings, maybe as a custom object
>
> These elements can be in six states. The first five are sequential;
> elements try to go through them in turn:
>
>    - idle (the initial state at creation time)
>    - prefetching...
>    - ready (matches the .ready promise)
>    - loading...
>    - loaded (matches the .loaded promise)
>
> ...and the sixth is "error", meaning something failed permanently.
>
> Setting src="", or whatever causes the element's state to be reset,
> immediately rejects the preexisting .loaded promise and creates a new
> one, moving the element back to "idle".
>
> When an element is created, it's added to the ES6 module registry. (When
> one of these elements has its ID or URL changed, its entries in the
> registry are updated.) The ES6 LoadModule() operation is called for this
> module (that's how it is added to the registry).
>
> Except if the load policy has the "force" flag, when the element is added
> to the registry it's done in such a way as to rely on ES6 deduping.
>
> An element can be needed. By default it's not, unless it has a load-policy
> of "block" or "async". Upon creation, and when its needs="" is changed
> while the element is still not ready, or when another element's ID is
> changed and that matches an ID in an element's needs="", the element's
> [[Dependencies]] list is updated accordingly.
>
> When an element is marked as needed, all the things in its
> [[Dependencies]] get marked as needed also.
>
> An element in "idle" moves to "prefetching" if the load-policy is
> optimistic and the browser has nothing better to do, or the load-policy
> has "precache" declared and the browser has nothing to do, or the element
> is marked as "needed" somehow.
>
> An element's "fetch" hook blocks until the element reaches "prefetching".
> Once it does, if this is something to download, it creates a Request
> object from the load-settings="" attribute and the appropriate URL. For
> inline scripts and styles, the body comes from the element. Once the fetch
> hook finishes, an event is to be fired at the element. Once all its
> dependencies are ready, another event is to be fired at the element.
>
> When a script is needed, once it's ready, it is EnsureEvaluated() (see
> the ES6 spec for details).
>
> When scripts run, if they throw an uncaught exception then they go to the
> "error" state and that prevents any dependencies from resolving. If
> something is being loaded and it depends on something that's reached
> "error", it aborts loading. Something that depends on a resource in the
> "error" state won't load, it'll just transition to "error" straight away.
> (Or should it just wait, so you can remove the dependency and unblock it?)
>
> Changing the "load-policy" doesn't reset the element's state, it just
> causes it to resume from its current state with the new policy. If the new
> policy is irrelevant (because it applies to a state earlier than the
> current one), then nothing interesting happens. For instance, moving from
> "block" to "declare" after the file has already been executed does nothing.
>
> For style elements (and most elements, in fact), the "execute" callback
> does nothing. The StyleSheet object is created earlier. The script is
> applied once it is both needed and ready (in place of EnsureEvaluated()).
> While it is marked with a load-policy of "declare", subsequent fetches of
> the same URL in a style sheet context in the same Loader will use the same
> file, not refetch it.
>
> Certain loadable elements can also be told to execute by the browser even
> when they are awaiting being needed. Notably, <video>, <audio>, <img>,
> <object>, and <iframe> will self-need themselves if the come into view.
>
> The <link rel=preload> feature is given an attribute, kind="", which it
> can use to determine how to parse the file (image, style sheet, HTML
> import, JS script, JS module, ...).
>
> Documents add things like synchronous scripts, style sheets, deferred
> scripts, images, etc, to their dependency list while they are loading.
>
> When a Document loads, all the <script defer> elements are told they
> are needed.
>
> Elements that aren't one of these "loadable" elements that end up being
> imported as ES6 modules act as follows:
>
>  - fetch: blocks until the ID is visible
>  - instantiate: returns the element
>
> By default, the priority of loads is based on the load policy and whether
> the element is needed or not.
>
>
>
> Here's how this would handle the use cases listed above.
>
> > [Use-case F:] A website has a page where media is the primary content.
> > It would like to make sure that media is downloaded before JS [e.g.
> > flickr, youtube, facebook photos]
>
>    <!DOCTYPE HTML>
>    <html>
>     <title>Photo 23 in My Gallery</title>
>    <body>
>     <h1>Photo 23</h1>
>     <p><img src="photo23.jpeg" alt="..."></p>
>     <script src="more-features.js" load-policy="low-priority"></script>
>    </body>
>
>
> > [Use-case G:] A website knows there's a piece of Javascript code that
> > the user might need if they click on a part of the page. The developer
> > would like to have the user download it, but not at the expense of other
> > resources.
>
>    <script src="button-reaction.js" id="reaction"
>            load-policy="when-needed precache low-priority">
>     // button-reaction.js defines react()
>    </script>
>    <button type=button
>            onclick="document.scripts.reaction.load().then(
>                     function() { react(); })"> Part of the Page </button>
>
>
> > [Use-case H:] A website is prefetching photos in a photo album and would
> > like to make sure these images are lower priority than images the user
> > is actually viewing.
>
>    <img src="photo1.jpg" alt="..." load-policy="when-needed precache">
>    <img src="photo2.jpg" alt="..." load-policy="when-needed precache">
>    <img src="photo3.jpg" alt="..." load-policy="when-needed precache">
>    <img src="photo4.jpg" alt="..." load-policy="when-needed precache">
>    <img src="photo5.jpg" alt="..." load-policy="when-needed precache">
>
> As they come into view, they'll become needed automatically. When they are
> not needed, they get precached if that wouldn't get in the way of other
> things getting loaded.
>
>
> On Mon, 28 Jul 2014, Ben Maurer wrote:
> >
> > [Use-case I:] Facebook uses an automated pipeline to decide what CSS/JS
> > files to package together. If we could pass a custom header in the
> > request for a CSS file (for example: what part of the page caused that
> > file to be loaded) we could use this information in our packaging system
> > to make smarter decisions.
>
>    <link rel=stylesheet href="..."
>          load-settings='{ "headers": { "X-Facebook-Blame" : "<head>" } }'>
>
> ...or some such. The exact syntax of load-settings="" isn't something I've
> studied closely. It might make sense to have a more dedicated syntax,
> since JSON doesn't work well in HTML attributes due to quoting rules.
>
> From script:
>
>    var style = document.createElement('link');
>    style.rel = 'stylesheet';
>    style.href = '...';
>    style.loadSettings = { "headers":
>                              { "X-Facebook-Blame" : "<head>" }
>                         }.toJSON();
>
> ...or some such. Again, it might make sense to have a dedicated API for
> loadSettings which would make this better. Also, medium term, Tab is
> working on a StyleSheet object and constructor.
>
>
> > [Use-case J:] The way we render pages at Facebook [is essentially that
> > we] flush sections of HTML with a list of CSS and JS dependencies for
> > each section. The HTML is only rendered once these resources are loaded.
>
> We could have dedicated features for this (like making any element depend
> on any other, making <div>s whose dependencies aren't met be display:none,
> or even having :loaded/:ready pseudo-classes to match elements based on
> their dependencies' statuses) but for now, even with the stuff above, the
> simplest solution is probably more or less what you'd do now:
>
>    <section hidden class="foobar">
>     <!-- this is the section of HTML mentioned in the use case -->
>     <!-- each dependency is listed explicitly: -->
>     <script>
>      // Prior to this we must have loaded a script that defines two
>      // functions. The first adds style sheets, the second adds scripts.
>      // They return promises. All the things added by these functions are
>      // fetched right away.
>      var promises = [];
>      // To add a style sheet, you need to know the URL to the sheet,
>      // any sheets it depends on, and the relative order amongst
>      // all the sheets in the project
>      promises.push(addStyleSheet('common.css', [], 1));
>      promises.push(addStyleSheet('foobar.css', ['common.css'], 4));
>      // To add a script, you just need the URL and its dependencies.
>      promises.push(addScript('common.js', []));
>      promises.push(addScript('foobar.js', ['common.js']));
>      var section = document.currentScript.parentNode;
>      Promise.all(promises).then(function () {
>        section.hidden = false;
>      })
>     </script>
>    </section>
>
> Depending on the size of your total dependency tree, you could predeclare
> it in the <head> and just refer to that from import statements, something
> like:
>
>    <link rel=stylesheet load-policy="declare when-needed"
>                         href="common.css">
>    <link rel=stylesheet load-policy="declare when-needed"
>                         href="foobar.css" needs="common.css">
>    <script src="common.js" load-policy="declare when-needed"></script>
>    <script src="foobar.js" load-policy="declare when-needed"
>                         needs="common.js"></script>
>
> ...and then later when you send the markup:
>
>    <section hidden class="foobar">
>     <!-- this is the section of HTML mentioned in the use case -->
>     <!-- each dependency is listed explicitly: -->
>     <script type="module">
>      import "./foobar.css";
>      import "./foobar.js";
>      document.currentScript.parentNode.hidden = false;
>     </script>
>    </section>
>
> If you gave the <link> and <script> blocks IDs, you could refer to them
> that way instead, to be more explicit:
>
>    <link rel=stylesheet load-policy="declare when-needed"
>                         href="common.css" id=common-css>
>    <link rel=stylesheet load-policy="declare when-needed"
>                         href="foobar.css" id=foobar-css
>                         needs="common.css">
>    <script src="common.js" load-policy="declare when-needed"
>                         id=common-script></script>
>    <script src="foobar.js" load-policy="declare when-needed"
>                         needs="common.js" id=foobar-script></script>
>
>    ...
>
>    <section hidden class="foobar">
>     <!-- this is the section of HTML mentioned in the use case -->
>     <!-- each dependency is listed explicitly: -->
>     <script type="module">
>      import "#foobar-css";
>      import "#foobar-script";
>      document.currentScript.parentNode.hidden = false;
>     </script>
>    </section>
>
> However, giving all the dependencies ahead of time doesn't really scale
> for even medium-sized sites, unfortunately.
>
>
> > [Use-case K:] We have a few other use cases for this type of dependency
> > (for example, we have a method where you can say "call this callback
> > once resources X, Y and Z are requested").
>
>    Promise.all([X.loaded, Y.loaded, Z.loaded]).then(thisCallback)
>
>
> > [Use-case L:] A web page wants to load and execute a script widget.js if
> > the script is already cached in the browser.  However, it wants to load
> > other essential assets such as images first if it's not already in the
> > cache except as long as the user had not started interacting with the
> > parts of the page that require widget.js.
>
>    <script id=w src=widget.js load-policy="optimistic low-priority">
>    </script>
>
>    <div> <!-- part of the page that needs the widget -->
>     <script>
>      var div = document.currentScript.parentNode;
>      function startWidget () {
>        document.scripts.w.load();
>        div.removeEventListener('mouseover', startWidget, true);
>        div.removeEventListener('focus', startWidget, true);
>      };
>      div.addEventListener('mouseover', startWidget, true);
>      div.addEventListener('focus', startWidget, true);
>     </script>
>    </div>
>
>
> > [Use-case M:] Being able to specify that an image/video should only be
> > downloaded "on demand" (aka "lazily"), i.e. when it's in view, or about
> > to be in view. Use case is both to lower bandwidth in cases of long
> > pages where the user doesn't always scroll to the bottom, as well as
> > make sure to fill the network pipe with the most important resources
> > first.
>
>    <img src="..." alt="..." load=policy="when-needed">
>
>
> > [Use-case N:] Being able to specify that a stylesheet should not block
> > rendering. Use case is to preload stylesheets that will be used by
> > content that isn't rendered in the initial view, but that might be
> > rendered later.
>
> There's various options here. If we're going to explicitly invoke the
> style sheet in due course:
>
>    <link rel=stylesheet href="..." id="mystyle"
>          load-policy="when-needed precache">
>
>    // when needed:
>    document.getElementById('mystyle').load();
>
> If we're just hoping it'll be loaded slower, but will be applied
> automatically:
>
>    <link rel=stylesheet href="..." id="mystyle"
>          load-policy="async low-priority">
>
> Medium term we might want to consider letting random elements depend on
> the style sheet, not just <img>, so that when the elements that do use
> this come into view, the style sheet can be forced on (and maybe the
> aforementioned pseudo-classes can be used to display:none the element
> while it's loading the style sheet or something.)
>
>
> > [Use-case O:] Being able to specify some form of prioritization for
> > resources like (non-blocking) stylesheets, (non-blocking) <script>s,
> > images, video, iframes etc. Use case is making sure to fill the network
> > pipe with the most important resources first. Possibly a simple
> > prioritization like "needed for initial rendering/not needed for initial
> > rendering" is enough, possibly there are needs for more finegrained
> > prioritization like "needed for initial rendering/needed for page
> > feature X that is commonly used, needed for other".
>
> The low-priority flag should help with this. To give more control, if
> RequestInit (part of Fetch) exposes HTTP2's priorities, authors can
> directly manipulate that.
>
>
> > [Use-case P:] download dynamic page components (e.g. maps) only on
> > larger devices.
>
> Long term, we could add a media="" attribute to <script> to make this
> easier. Short term, you can do it with scripts by checking the width of
> the device and calling load() on the script if you want it.
>
> If you're a browser vendor who wants to implement <script media>, please
> comment on this bug:
>
>    https://www.w3.org/Bugs/Public/show_bug.cgi?id=23509
>
>
> > [Use-case Q:] I am dynamically loading one of those social widgets that,
> > upon load, automatically scans a page and renders social buttons. I need
> > to be able to preload that script so it's ready to execute, but decide
> > when I want it to run against the page. I don't want to wait for true
> > on-demand loading, like when my user clicks a button, because of the
> > loading delay that will be visible to the user, so I want to pre-load
> > that script and have it waiting, ready at a moment's notice to say "it's
> > ok to execute, do it now! now! now!".
>
> You'd declare it like this:
>
>    <script ... load-policy="when-needed precache" id=w>
>
> ...and run it like this:
>
>    document.scripts.w.load();
>
>
> > [Use-case S:] One CMS plugin wants to load "A.js" and "B.js", where B
> > relies on A. Both need to load in parallel (for performance), but A must
> > execute before B executes. I don't control A and B, so changing them is
> > not an option. This CMS plugin [wants] to wait for some
> > user-interaction, such as a button click, before executing the code. We
> > don't want there to be any big network-loading delay visible to the user
> > between their click of the button and the running of that plugin's code.
>
>    <script src="a.js" load-policy="when-needed precache" id=a>
>    <script src="b.js" load-policy="when-needed precache" needs=a id=b>
>
>    <input type=button onclick="document.scripts.b.load()">
>
>
> > Another CMS plugin on this same page wants to load "A.js", "C.js", and
> > "D.js". This plugin doesn't know or care that the other plugin also
> > requests "A.js". It doesn't know if there is a script element in the
> > page requesting it or not, and it doesn't want to looking for it. It
> > just wants to ask for A as a pre-requisite to C and D. But C and D have
> > no dependency on each other, only a shared dependency on A. C and D
> > should be free to run ASAP (in whichever order), assuming that A has
> > already run [once] some user-interaction that initiates the load of A,
> > C, and D. This user interaction may be before the other plugin requested
> > A, or after it requested A.
>
> First the previous part:
>
>    <script src="a.js" load-policy="when-needed precache" id=a1>
>    <script src="b.js" load-policy="when-needed precache" needs=a1 id=b1>
>    <input type=button onclick="document.scripts.b1.load()">
>
> Now this plugin:
>
>    <script src="a.js" load-policy="when-needed precache" id=a2>
>    <script src="c.js" load-policy="opportunistic precache" needs=a2 id=c2>
>    <script src="d.js" load-policy="opportunistic precache" needs=a2 id=d2>
>    <input type=button
>         onclick="document.scripts.c2.load(); document.scripts.d2.load();">
>
> Because the load-policy doesn't contain "force" (which would be in the
> default for scripts), the second <script src="a.js"> defers to the first
> one.
>
>
> > "A.js" can be requested relatively (via a <base> tag or just relative to
> > document root) or absolutely, or it might be requested with the
> > leading-// protocol-relative from, taking on whatever http or https
> > protocol the page has, whereas other references to it may specify the
> > prototcol.
>
> That just works with the above, since the src="" attribute is resolved
> before being compared.
>
>
> > These plugins can't guarantee what ID's or classes they use are reliably
> > unique without undue processing burden.
>
> Ah. This is more problematic.
>
> If the plugins are put into HTML imports, this works because imports have
> their own ID scope. Is that sufficient?
>
>
> > [Use-case T:] I have two different calendar widgets. I want to pop one
> > of them up when a user clicks a button. The user may never click the
> > button, in which case I don't want the calendar widget to have ever
> > executed to render. [...]
> >
> > It'd be nice if both calendar widgets were built sensibly so that
> > loading the code didn't automatically render. One of them IS, the other
> > is unfortunately mis-behaving, and it will render itself as soon as its
> > code is run. [...]
> >
> > Furthermore, these two widgets are not "equal". Perhaps one is better
> > for smaller browser window sizes, and the other is better for larger
> > browser windows. [...]
> >
> > Regardless, the point is, there's run-time conditions which are going to
> > determine if I want to execute calendar widget A or B, or maybe I never
> > execute either. But I want them both preloaded and ready to go, just in
> > case, so that if the user DOES need one, it's free and ready to execute
> > with nearly no delay, instead of having to wait to request as I would
> > with only on-demand techniques.
>
>    <script src="calendar1.js" load-policy="when-needed precache" id=cal1>
>    </script>
>    <script src="calendar2.js" load-policy="when-needed precache" id=cal2>
>    </script>
>
>    <script>
>     function showCalendar() {
>       if (useCalendar1)
>         document.scripts.cal1.load();
>       else
>         document.scripts.cal2.load();
>     }
>    </script>
>
>    <input type=button onclick="showCalendar()">
>
>
> > [Use-case U:] I have a set of script "A.js", "B.js", and "C.js". B
> > relies on A, and C relies on B. So they need to execute strictly in that
> > order. [Now], imagine they progressively render different parts of a
> > widget. [...] I only want to execute A, B and C once all 3 are preloaded
> > and ready to go. It's [...] about minimizing delays between them, for
> > performance PERCEPTION.
> >
> > [For example, one of them might start playing a video, and another might
> > introduce the <canvas> slides for that video. You want all of the
> > relevant scripts to be run at once, so there's no point where the page
> > has a <video> element but doesn't have the <canvas>.]
>
>    <script src="A.js" id=A load-policy="late-run"></script>
>    <script src="B.js" id=B load-policy="late-run" needs=A></script>
>    <script src="C.js" id=C load-policy="async" needs=B></script>
>
>
> > [Use-case V:] you have a string of scripts ("A.js", "B.js", and "C.js")
> > loading which constitute a dependency chain. A must run before B, which
> > must run before C. However, if you detect an error in loading, you stop
> > the rest of the executions (and preferably loading too!), since clearly
> > dependencies will fail for further scripts, and the errors will just
> > unnecessarily clutter the developer console log making it harder to
> > debug.
>
> That's the built-in behaviour.
>
>
> > [Use-case W:] some developers have even requested to be able to stop the
> > chain and prevent further executions if the script loads, but there's
> > some compile-time syntax error or run-time error that happens during the
> > execution. For them, it's not enough for B to simply finish loading
> > successfully, but that it must fully execute without error.
>
> If something throws, it'll trigger the same failure behaviour as failing
> to load at all.
>
>
> > [Use-case X:] not all dependencies are JS files, e.g. authors use
> > plugins to load template files, JSON, images, etc.
>
> Images are handled since you can use an <img> element as the target of a
> needs="" attribute. You can add dependencies on manually-started loads
> using promises; these won't automatically trigger the loads, but they
> will cause the loads to wait.
>
>
> > [Use-case Y:] not all dependencies are usefully satisfied immediately
> > after their JS file is loaded, e.g. some libraries may need asynchronous
> > initialization.
>
> You can add a promise as a dependency.
>
>
> > [Use-case Z:] Another common kind of dependency scripts have is presence
> > of certain element in the DOM, e.g. `dropdown-menu.js` may require `<nav
> > id="menu">` to be in the document _and_ have its content fully parsed
> > before the script can run.
>
> needs="" can point to any element by ID; it'll only be resolved once the
> ID is present in the DOM.
>
>
> On Tue, 27 Aug 2013, Ian Hickson wrote:
> >
> > Jake also mentioned these requirements:
> >
> > | - Provides an adoption path for browsers that don't support the new
> > |   feature (happy for the fallback to be blocking document-order
> > |   execution)
>
> That's the fallback for the declarative features. (This might actually
> be a problem for load-policy=declare.)
>
>
> > | - Is discoverable by pre-parsers (so async=false and old-IE's
> > |   readystate methods aren't enough)
>
> This is true for the declarative cases, at least. Note though that if
> we make everything async (as this essentially would), preparsing
> becomes much less important.
>
>
> > And Kyle mentioned this scenario that we need to handle as well (not
> > strictly a use case, more a variant on the above use cases):
> >
> > > I want to preload a script which is hosted somewhere that I don't
> > > control caching headers, and to my dismay, I discover that they are
> > > serving the script with incorrect/busted/missing caching headers.
>
> We can handle this by defining the behaviour of "precache" more
> explicitly, or putting options or load-settings="", but I'm not sure
> what behaviour we want exactly. What headers should we ignore? When?
>
>
> On Wed, 23 Jul 2014, Ben Maurer wrote:
> > On Tue, Jul 22, 2014 at 5:33 PM, Ian Hickson <ian@hixie.ch> wrote:
> > >
> > > Why not:
> > >
> > >    var mystyle = E('link', { rel: 'stylesheet', href: 'my.css',
> > > whenneeded: true });
> > >    document.body.appendChild(mystyle);
> > >    var myfetch = mystyle.fetch;
> > >    ...
> >
> > Yeah, I think that API would be perfect (assuming that whenneeded=true
> > initiates the fetch, but not the load into the document). In combination
> > with allowing the user to specify an attribute with a set of parameters
> > to the fetch algorithm (eg, a custom header) I think that would cover
> > the use cases I was thinking of.
>
> So this would be:
>
>    var mystyle = E('link',
>                    { rel: 'stylesheet', href: 'my.css',
>                      'load-policy': 'declare prefetch',
>                         // declare prevents it from ever being applied
>                      'load-settings': '...'
>                         // this is your custom headers, etc
>                    });
>    document.body.appendChild(mystyle);
>    mystyle.load(); // triggers the fetch
>     // since it's marked "declare", it doesn't get automatically applied
>    mystyle.loaded.then(function () {
>      // we can remove the 'declare' part of the policy to make it apply:
>      mystyle.loadPolicy.remove('declare');
>      // alternatively we could create a new <link rel=stylesheet> element
>      // and insert that; since the URL is the same it would reuse what it
>      // got for mystyle instead of starting anew.
>    });
>    var myfetch = mystyle.request;
>    // you can manipulate the priority or whatever with myfetch
>
> --
> Ian Hickson               U+1047E                )\._.,--....,'``.    fL
> http://ln.hixie.ch/       U+263A                /,   _.. \   _\  ;`._ ,.
> Things that are impossible just take longer.   `._.-(,_..'--(,_..'`-.;.'

Received on Monday, 25 August 2014 20:54:27 UTC