Re: [whatwg] Preloading and deferred loading of scripts and other resources
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
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
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
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