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

2014-09-08 Thread Ian Hickson

I got some feedback on my last e-mail to the effect that having the 
proposal sandwiched between the rationale and the examples of how it would 
be used made it hard to find, so I'm reproducing the proposal here 
(slightly updated based on feedback):

---
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.

   loadpolicy= 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. The
 keywords' meanings are as follows:

  block - stop parsing until this resource is
  applied

  async - fetch now, apply asap

  optimistic - fetch when needed, apply asap

  when-needed - fetch when needed, apply when
  needed

  declare - fetch when needed, don't apply

  precache - for fetch with needed, consider
  fetching earlier

  low-priority - let other things go first

  force - always fetch anew, don't de-dupe


   loadsettings=   A JSON-encoded dictionary to pass to the Request
 constructor. (Or some other syntax. Proposals
 welcome. JSON isn't great in an attribute.)

...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).

   .readyPromise 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.

   .needsreflects 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
loadpolicy 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 loadpolicy is
optimistic and the browser has nothing better to do, or the loadpolicy
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 

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

2014-09-08 Thread Ilya Grigorik
On Mon, Sep 8, 2014 at 1:33 PM, Ian Hickson i...@hixie.ch wrote:

  I really like your proposal for as=... Concretely it could look
 something
  like this:
 
  link rel=preload
  href=/some/asset.css
  as=stylesheet(used to initialize default priority, headers,
  etc)
  load-settings={}  (JSON payload with custom headers, priority
  [2], etc)
  media= ...  (relevant media queries..)
  probability=([0.0-1.0] used for speculative fetches
 [3])
  

 I don't understand why this would be better than:

link rel=stylesheet loadpolicy=declare href=/some/asset.ass
  loadsettings=... media=...


Better or worse is not the point. I think the current proposal fails to
address the larger underlying problem.

The platform is missing a lower-level primitive (declarative and
imperative) that is able to explain resource loading with the same
expressive power as requests initiated by the browser itself. XHR provides
arbitrary resource loading, but it lacks the power to express
transport-layer options such as relative request priority and dependencies,
and it also hides requests from the preload scanner, which is a deal-break
for performance. To address this, we need two things:

(1) Fetch API with load-settings addresses the imperative side of the
problem.
(2) We also need a declarative, content-type agnostic primitive to express
resource loads, such that the preload scanner is able to pickup and
processes these fetches on par with all other resources -- hence my
rel=preload suggestion [1].

We can augment img, script, and other elements, with load-settings and
other flags, but that still doesn't cover all the necessary cases. For
example, how do I fetch a font file, or an arbitrary JSON payload with
app-data, etc? Note that I'm looking for declarative syntax that allows me
to set arbitrary fetch priorities - e.g. upgrade my JSON payload to high
priority because I need it to render content on the screen. This is the
part that we *need* to solve.

Once we have the low-level declarative+imperative primitives for loading
resources, we can build up all other loading and dependency patterns in
app-space. The loadpolicy/needs attributes are syntax sugar for select
resource types -- nice, but (IMO) not strictly necessary and not sufficient
for the more general case of content-types not covered by dedicated
elements.

ig

[1] https://igrigorik.github.io/resource-hints/#preload


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

2014-09-08 Thread Ian Hickson
On Mon, 8 Sep 2014, Ilya Grigorik wrote:
 
 Better or worse is not the point. I think the current proposal fails to 
 address the larger underlying problem.

If it did, then that would be worse.


 The platform is missing a lower-level primitive (declarative and 
 imperative) that is able to explain resource loading with the same 
 expressive power as requests initiated by the browser itself.

That isn't a problem.


 XHR provides arbitrary resource loading, but it lacks the power to 
 express transport-layer options such as relative request priority

That is fixed by exposing Request initialisation flags on XHR.

 and dependencies,

That's fixed by using the proposal in this thread.

 and it also hides requests from the preload scanner, which is a 
 deal-break for performance.

That's why the proposal in this thread uses the existing import mechanisms 
to define how the dependencies.


 (2) We also need a declarative, content-type agnostic primitive to 
 express resource loads, such that the preload scanner is able to pickup 
 and processes these fetches on par with all other resources -- hence my 
 rel=preload suggestion.

I don't disagree that we need a way to declarative way to import 
non-browser-native resources (like some text file the script uses for 
storing game level data or something). But I don't think we need a 
redundant mechanism to import resource types that already have existing 
import mechanisms. That's not a primitive, it's just a redundant 
mechanism.

I went into more detail on this very topic, considering a wide array of 
options, in the big e-mail I sent recently:

   http://lists.w3.org/Archives/Public/public-whatwg-archive/2014Aug/0177.html


 We can augment img, script, and other elements, with load-settings and 
 other flags, but that still doesn't cover all the necessary cases. For 
 example, how do I fetch a font file

   http://dev.w3.org/csswg/css-font-loading/

...which presumably would have loadSettings exposed.


 or an arbitrary JSON payload with app-data, etc?

XHR, or link rel=preload. I assume you're not expecting us to preparse 
the JSON file.


 Note that I'm looking for declarative syntax that allows me to set 
 arbitrary fetch priorities - e.g. upgrade my JSON payload to high 
 priority because I need it to render content on the screen. This is the 
 part that we *need* to solve.

rel=preload with the proposal on this thread handles this fine, as far as 
I can tell.


 Once we have the low-level declarative+imperative primitives for loading 
 resources, we can build up all other loading and dependency patterns in 
 app-space.

That people have to build them in app space is the bug I'm trying to fix 
here.


 The loadpolicy/needs attributes are syntax sugar for select resource 
 types -- nice, but (IMO) not strictly necessary and not sufficient for 
 the more general case of content-types not covered by dedicated 
 elements.

needs= is actually very little more than syntactic sugar over ES6 module 
loader primitives, assuming that we can get the ES6 module loader to be 
augmented to address the needs of non-ES resources:

   http://esdiscuss.org/topic/es6-loader-proposed-changes

-- 
Ian Hickson   U+1047E)\._.,--,'``.fL
http://ln.hixie.ch/   U+263A/,   _.. \   _\  ;`._ ,.
Things that are impossible just take longer.   `._.-(,_..'--(,_..'`-.;.'


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

2014-09-08 Thread Ilya Grigorik
On Mon, Sep 8, 2014 at 7:59 PM, Ian Hickson i...@hixie.ch wrote:

  The platform is missing a lower-level primitive (declarative and
  imperative) that is able to explain resource loading with the same
  expressive power as requests initiated by the browser itself.

 That isn't a problem.


I don't follow. To me that *is* the core problem that we should solve first
and ship as soon as possible: if we keep the surface area low, we can ship
it quickly and let developers experiment and move the platform forward.
Adding more layers of higher-level APIs only slows the deployment process.

To be clear, I'm not against the core premise of unifying various import
mechanisms, but to me that's a secondary goal -- good housekeeping, but not
the problem that the actual web developers (not implementers) are actually
up against today. And, at least personally, I think we should prioritize
developer needs over implementers. That said, I don't think we're actually
that far apart...


  XHR provides arbitrary resource loading, but it lacks the power to
  express transport-layer options such as relative request priority

 That is fixed by exposing Request initialisation flags on XHR.


I've seen discussions about exposing this on Fetch, but not XHR. Granted,
one is not far from the other.


  and dependencies,

 That's fixed by using the proposal in this thread.


We're talking about different dependencies. I mean transport-layer
dependencies - i.e. if possible, ship bytes for resource A before bytes for
resource B. Again though, if we can express priorities, we should be able
to express (transport) dependencies via the same mechanism, so this is not
a big deal.


  and it also hides requests from the preload scanner, which is a
  deal-break for performance.

 That's why the proposal in this thread uses the existing import mechanisms
 to define how the dependencies.


But restricts it to a subset of resource types. Granted, this is not an
issue if you give me a generic way to load any resource, ala rel=preload.


  (2) We also need a declarative, content-type agnostic primitive to
  express resource loads, such that the preload scanner is able to pickup
  and processes these fetches on par with all other resources -- hence my
  rel=preload suggestion.

 I don't disagree that we need a way to declarative way to import
 non-browser-native resources (like some text file the script uses for
 storing game level data or something). But I don't think we need a
 redundant mechanism to import resource types that already have existing
 import mechanisms. That's not a primitive, it's just a redundant
 mechanism.

 I went into more detail on this very topic, considering a wide array of
 options, in the big e-mail I sent recently:


 http://lists.w3.org/Archives/Public/public-whatwg-archive/2014Aug/0177.html


It's only redundant insofar as XHR is a redundant mechanism for loading
arbitrary resources. There are cases where fetching an image / stylesheet /
etc, via XHR is both a reasonable and a required step -
{pre,post}processing, and so on. Moving forward, I think the intent is to
explain resource loading via Fetch. I'm asking for a declarative Fetch
that's preloader friendly and has the same expressive capabilities.


  We can augment img, script, and other elements, with load-settings and
  other flags, but that still doesn't cover all the necessary cases. For
  example, how do I fetch a font file

http://dev.w3.org/csswg/css-font-loading/

 ...which presumably would have loadSettings exposed.


Sadly, even that requires executing JavaScript and fails the preloader use
case.


  or an arbitrary JSON payload with app-data, etc?

 XHR, or link rel=preload. I assume you're not expecting us to preparse
 the JSON file.


Right, no execution. Just fetch and nothing else: start the request, stick
into the appropriate cache(s) if applicable, and keep the payload inert.


  Note that I'm looking for declarative syntax that allows me to set
  arbitrary fetch priorities - e.g. upgrade my JSON payload to high
  priority because I need it to render content on the screen. This is the
  part that we *need* to solve.

 rel=preload with the proposal on this thread handles this fine, as far as
 I can tell.


Yes, I think it's close! A few considerations to account for in the
processing model, based on real-world use cases and feedback from the
webperf group:
- https://igrigorik.github.io/resource-hints/#preload
- *https://igrigorik.github.io/resource-hints/#processing
https://igrigorik.github.io/resource-hints/#processing*

All I'm arguing for here is that the MVP for giving web developers the
power to start solving these problems is rel=preload. Everything else is a
nice to have. As a result, I'd love to uncouple rel=preload from the
rest... Once/if the other mechanisms are ready, rel=preload would just
inherit them as part of coverage of link. As I said earlier, I don't
think we're that far apart.

ig