A user account is required in order to edit this wiki, but we've had to disable public user registrations due to spam.

To request an account, ask an autoconfirmed user on Chat (such as one of these permanent autoconfirmed members).

Talk:Dynamic Script Execution Order: Difference between revisions

From WHATWG Wiki
Jump to navigation Jump to search
(more response regarding multiple loading queues)
Line 132: Line 132:
I have to admit, you raise a valid point with respect to that common usage. The YUI model (where the framework is responsible for all loading) is perhaps the more appropriate model to move toward, though. Or, the framework doesn't auto-load its own dependencies at all. In either case, I think it's cleaner to have one loading mechanism in play rather than two or more competing ones, because as you point out, this is going to get messy. I still am not sure this means that the async=false proposal is lacking, because as I think about how complicated such a split loading would be with your `readyState` proposal, that seems even worse/more complicated to me. [[User:Getify|Getify]] 20:06, 15 December 2010 (UTC)
I have to admit, you raise a valid point with respect to that common usage. The YUI model (where the framework is responsible for all loading) is perhaps the more appropriate model to move toward, though. Or, the framework doesn't auto-load its own dependencies at all. In either case, I think it's cleaner to have one loading mechanism in play rather than two or more competing ones, because as you point out, this is going to get messy. I still am not sure this means that the async=false proposal is lacking, because as I think about how complicated such a split loading would be with your `readyState` proposal, that seems even worse/more complicated to me. [[User:Getify|Getify]] 20:06, 15 December 2010 (UTC)
</blockquote>
</blockquote>
 
<blockquote style="background-color:#eee">
I would not argue '''against''' a global queue for synchronized execution, I just think the usefulness of such a construct declines as scripts that "I don't care about" are added.  It's my opinion the spec should provide the ability for high-level code to implement similar constructs, regardless of how complex it may be to do so. <br/>
<br>
That being said, I don't think it's any more complicated than existing models.  Here's a demonstration of an [http://digital-fulcrum.com/executionorder/ IE-only parallel-loading, synchronously-executing script queue] implemented in 40 lines of code.  It tests both cached and un-cached scripts (from the LABjs test suite) and has been tested and found to be working in IE6-8.
<br>
[[User:Serverherder|Serverherder]] 01:52, 16 December 2010 (UTC)
</blockquote>
</blockquote>  
</blockquote>  


- James Burke
- James Burke

Revision as of 01:52, 16 December 2010

Please discuss the proposal here. All informal feedback is welcomed, and when it's appropriate, please add content to the main page.


What about CommonJS / RequireJS?

I'm not sure we need to complicate the HTML or browser engines in order to satisfy the advanced use cases. To me it seems that the JavaScript langauge itself could abstract the requirements and let the browser vendors implement whatever solution they see fit. Specifically, if JavaScript provided the define() and require() calls proposed in the CommonJS "specifications" (and implemented by RequireJS, dojo (trunk), and others *Yabble?), then browsers could just load and evaluate scripts as fast as possible without regard to script execution order.

This would solve all of the problems except for the current inability to use loaders like LABjs in FF4 or webkit. To solve that problem, we should consider keeping the existing functionality or triggering the deprecated functionality when needed.

--Unscriptable 01:29, 2 November 2010 (UTC)

Response

This is a valid point except that it assumes that all code that needs to be loaded is "modular"... in fact, most code on the internet that needs to be loaded is NOT modular, and instead requires particular ordering when being loaded... for instance, "jquery" and "jquery-ui" -- jQuery must be run before jQuery-UI is loaded and run.


The spirit of this proposal is to add the facility to native browser (rendering engine, specifically) behavior, such that any and all existing content is able to be loaded (even with dependencies and order) without modification.

Are we trying to codify how one would implement this HTML dynamically so I can achieve parallel loading but retain dependency that is inferred in the order?

<script src="jquery.js"> </script>
<script src="jquery-ui.js"> </script>


If so, we must consider the case in which the dependency itself loads additional code which the discussions around `async=false` or even text/cache do not account for. Serverherder 19:23, 15 December 2010 (UTC)

Dependent code should be modular

I completely agree, 99% of JavaScript in use today is NOT modular, but that's arguably because there was no built-in support to make it modular (IMHO, YMMV, RTFM, BBQ, ROFL). But that doesn't mean there aren't dependencies that span script files / script nodes. I don't know how many sites would be broken (or if there is any way to determine how many sites would be broken) if/when the latest browsers started loading and evaluating script-injected scripts out of order. It's not just LABjs-based sites. I'll bet many dojo and YUI sites will break, too (although I don't know this for a fact because I don't know exactly how their dynamic script loaders work).

In any case, breaking existing sites is a BAD IDEA. :) There should be some way to allow LABjs and other dynamic script loaders to continue to work.

The part I don't agree with in the proposals is that it should be the job of HTML and/or the browser engine to manage dependencies. Specifically, I am talking about the scriptGroup element and the "waitFor" attribute. The "async" attribute may be the right level: it appropriates only general heuristics to the browser: load these scripts whenever you like, but load these other scripts in this order.

Detailed dependency management belongs in the modules, though. This is how it's done in most environments / languages: import statements, include statements, etc. It's no different in JavaScript, if a developer wants to take advantage of some code in another module, she/he should import it into their current module. This should be the model moving forward. It's not hard, it's not un-web-like, and it's already being done.

Existing code can be made to work modularly, too:

1. Identify modules and wrap them with a define() method. 2. Identify dependencies using either the Asynchronous Module Definition format or the CommonJS synchronous format

async format:

define(['dependency1', 'dependency2'], function (dependency1, dependency2) {
	/* this is the factory function, return the module inside here */
	return { /* some object, but could also be a constructor or a function */ };
});

sync format:

define(function (require, exports, module) {
	/* this is the factory function, require dependencies and return the module inside here */
	var dependency1 = require('dependency1');
	var dependency2 = require('dependency2');
	return { /* some object, but could also be a constructor or a function */ };
});

In the async case, the browser may employ whatever method it sees fit (e.g. parallel) to download the dependencies since the code inside the factory function won't execute until all of the dependencies are loaded and evaluated. In the sync case, the browser has no choice but to download and evaluate the dependency before continuing code execution. It's conceivable that the browser could find and asynchronously pre-fetch the inline require()'ed dependencies in the sync case. (RequireJS doesn't quite do this. Instead I believe it finds the inline require() calls and converts the module to an async module.)

So, in short: don't break LABjs (or any other script loaders), but don't extend the spec to manage dependency management from HTML.

--Unscriptable 01:29, 2 November 2010 (UTC)

Response #2

The cat's already out of the bag... we've got a dozen+ years worth, hundreds of millions of javascript files out there, which are NOT modular, and will not be modified to be modular.

If we're talking about either trying to change all the JS on the web to be modular, or trying to extend the HTML markup spec to include a better facility for accomodating the existing script content, I think the former is idealistic and "correct" but the latter is realistic and "right".

A modular loading system will only work for modular code, but a general loading mechanism in HTML (like the <script> tag) can load both modular and non-modular code, which is why that more general mechanism is what's in HTML right now and not some more specialized loading API that only loads a small percentage of JavaScript code out there.

The <script> tag has worked fine forever, and there's been no real big push to do away with it in favor of having all loading handled by JavaScript -- in fact, that would be impossible because if you had no way to load JS onto the page with a <script> tag, then no JavaScript could run on a page to load more code. So I don't agree that we should stop adding functionality to the HTML loading mechanism and only focus on JavaScript.

If we agree that the <script> tag itself is not only required but normative, then I'm not sure why decorating the <script> tag with additional behavior to help it be more powerful is a bad pattern. We've addded "defer" and "async" already. I'm not sure I understand why adding a wrapper tag called "scriptGroup" would be that much different than attributes on the <script> tag?

I also don't think that "scriptGroup" constitutes "dependency management". "scriptGroup" is a semantic way for a web author to express that they want to group a set of scripts together ONLY so far as execution order behavior is concerned. It implies nothing more to it (that "dependency management" would imply) than that.

For instance, consider this: if JavaScript had been built with non-global context and statement level context and sandboxing and such things, we'd have a much more secure JavaScript right now. But just because JavaScript may someday be taught some new tricks in terms of security, that doesn't mean that "now" HTML shouldn't try to help solve the problem. If for instance the <frag> tag can be used to create a sandboxed environment for third-party JavaScript code to run in, this is a much easier way to address the security problem than to suggest we have to wait for ES-Harmony to add extra syntax to the language to accomplish the same thing.

Getify 02:13, 2 November 2010 (UTC)

Text/cache solution

It seems to me that having a real text/cache script type, or a similar element that fires a load/error event and provides a .text property gets you where you need to be. You could setAttribute("type", "text/JavaScript") or use the text to create a new script element. Or a new style element, or whatever. That puts you in control of when script or CSS is interpreted. With async as the default, you don't need a new ordered attribute as that's easily managed in script.

"text/cache" response

On the surface, this idea sounds like it's pretty similar to <link rel=prefetch> -- in other words, we've already standardized a way to prefetch a resource into cache, and probably in a better way than the hack that I did in LABjs of just relying on it fetching unrecognizable content.

Unfortunately, it still suffers some similar problems to <link rel=prefetch>.

Firstly, if the notion is that you'd use <script type="text/cache"> to prefetch, and then you'd make a second request for the resource with a real <script type="text/javascript> node, it suffers the faulty assumption that the resource was served with proper cache headers.

If we try to avoid the need for the second request by suggesting that you can access the `text` property of the node (and then eval() or inject that code when you want to execute it), this runs afoul of the same-origin policy problem if you requested the script from a non-local domain.

The part of your suggestion that holds water would be if, given a "prefetched" script node that didn't execute yet, I could simply change that node's `type` value from "text/cache" to "text/javascript", and that would explicitly trigger the browser to immediately execute it.

This is an interesting idea. I can see though that it perhaps has some potential complications.

For instance, would the browser have to keep a "hasExecuted" internal flag, so that changing the `type` value would only at most result in one execution? Also, if the script node in question is loaded but not executed, can the page alter the script code (by setting its `text` property) before making the change to the `type` value? In that case, should the browser execute the original code or the modified code? I can see security implications and confusion abounding in that behavior.

Lastly, as mentioned above, this basically copies (in a similar but not exactly identical way) the <link rel=prefetch> behavior. It may be seen as a negative to be trying to step on the toes of <link rel=prefetch>, and also it may be more confusing to the general public as to why you'd use one technique or the other, given their differences being so nuanced.

That having been said, I can see that it's a viable alternate proposal. It's worth adding a note to that section of the main Wiki page and to getting some feedback from browser vendors on if they feel this is a more realistic/suitable solution to the use-case.

The difference between pre-fetching and this proposal seems pretty clear: Prefetching, if not performed now, will eventually be done once the user explicitly requests the page. while the "text/cache" solution indicates that the resource should load immediately, not during idle time.


Serverherder 19:10, 15 December 2010 (UTC)

Getify 20:56, 4 November 2010 (UTC)

RequireJS order support

I am the main developer for RequireJS, and just want to voice my support for a solution that works on the script element itself, either by leveraging the async attribute or allowing something like an "order" boolean attribute that would allow specifying a dynamically added script element should be executed in the order that it appears in the DOM. This capability should be something can be capability detected to avoid browser sniffing.

Why shouldn't dependency management be implemented in high-level code and the browser simply provide a means by which parallel loading can be achieved? As you know, there is a considerable amount of nuance. I'm of the opinion that implementing dependency management in the engine will eventually lead us right back to where we were 10 years ago with inline script tags which provides an easy method for dependency management at the expense of unmanaged blocking and an inability to detect or adapt to errors.
Serverherder 19:51, 15 December 2010 (UTC)

There are many scripts on the web today that have implicit dependencies that should be loaded in a specific order, but the application developer will want to use dynamically created script elements for best performance. jQuery plugins that depend on the jQuery script already been executed in the page are a good example.

Agreed, but I don't believe the proposals allow for proper emulation of the dependency management provided by script tags. Prototype.js, for example, loads its core modules dynamically (using document.write so maybe not the best example...). When prototype.js is included via script tags, ensuing script blocks are free to "depend" on all of these modules; Dynamically creating a dependency on prototype.js by loading both with the `async=true` property will fail since prototype.js won't be able to "jump the queue" and add insure its core modules load before its extensions.
Serverherder 19:51, 15 December 2010 (UTC)

I have to admit, you raise a valid point with respect to that common usage. The YUI model (where the framework is responsible for all loading) is perhaps the more appropriate model to move toward, though. Or, the framework doesn't auto-load its own dependencies at all. In either case, I think it's cleaner to have one loading mechanism in play rather than two or more competing ones, because as you point out, this is going to get messy. I still am not sure this means that the async=false proposal is lacking, because as I think about how complicated such a split loading would be with your `readyState` proposal, that seems even worse/more complicated to me. Getify 20:06, 15 December 2010 (UTC)

I would not argue against a global queue for synchronized execution, I just think the usefulness of such a construct declines as scripts that "I don't care about" are added. It's my opinion the spec should provide the ability for high-level code to implement similar constructs, regardless of how complex it may be to do so.

That being said, I don't think it's any more complicated than existing models. Here's a demonstration of an IE-only parallel-loading, synchronously-executing script queue implemented in 40 lines of code. It tests both cached and un-cached scripts (from the LABjs test suite) and has been tested and found to be working in IE6-8.
Serverherder 01:52, 16 December 2010 (UTC)

- James Burke