Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extended holdReady() to allow the ready event to be re-held after it has already fired #371

Closed
wants to merge 4 commits into from

Conversation

Projects
None yet
4 participants
@johncrenshaw
Copy link

commented May 5, 2011

Extended holdReady() to allow the ready event to be re-held after it has already fired. This is incredibly useful for complex AJAX applications, especially when combined with a script loader that uses holdReady. The specific use cases were:

  1. Add a hold while processing certain types of AJAX response
  2. Add a hold while the script loader loads any new includes from certain types of AJAX response

The result is that the ready event defers as expected for AJAX responses processed this way, opening the door to solve some of the more painful AJAX problems.

johncrenshaw johncrenshaw
Extended holdReady() to allow the ready event to be re-held after it …
…has already fired. This is incredibly useful for complex AJAX applications, especially when combined with a script loader that uses holdReady. The specific use cases were:

1. Add a hold while processing certain types of AJAX response
2. Add a hold while the script loader loads any new includes from certain types of AJAX response

The result is that the ready event defers as expected for AJAX responses processed this way, opening the door to solve some of the more painful AJAX problems.
@dmethvin

This comment has been minimized.

Copy link
Member

commented May 5, 2011

Can you show some scenarios where this might be useful, and add it to the 1.7 feature request pile? pile

@johncrenshaw

This comment has been minimized.

Copy link
Author

commented May 5, 2011

Yeah, I'll give you two answers. First one in code, second one an explanation of the theory behind what we're doing. It's a little long, sorry.

First, here is my overly simple code example:

===A Script Loader===
$.include = function(script)
{
$.holdReady(true);
add_script_to_document_and_call_function_when_loaded(
script,
function(){$.holdReady(false);}
);
}

===A Response From The Server===
...

<script> $.include("/js/mywidget.js"); $(function(){ // The expectation is that this code will not be executed until after mywidget.js has been loaded $("#widget51").mywidget({foo: "bar"}); }); </script>

...

The above works fine so long as this is the original page load (I.E. the ready event hasn't already fired.) With a vanilla jQuery 1.6 however, it will fail on an ajax request. In other words, the following is likely to give intermittent "mywidget is not a function" errors:

$("#content").html($.get("/mywidget.php"));

The errors happen because "ready" always lets everything through after the document has loaded, even if mywidget.js hasn't downloaded yet. The holdReady() event is ignored in the AJAX case. This is the documented behavior, but it isn't very helpful. My patch makes this work in both cases, by allowing holdReady() to restart the deferring process at any time.

The long answer is more about theory and architecture, not just on the client side, but also the server side. There are several competing needs that any web developer usually wants to balance:

  1. Keeping the code modular. Individual components should be self contained, and should be able to operate without sprinkling dependencies elsewhere.
  2. Minimizing the number of script files that need to be sucked down for any single request.
  3. Maximizing the value of the cache for script files.
  4. Keeping code organized. Separate things in separate files.
  5. Keeping development easy. "out of flow" things (like having to "rebuild" stuff each time you change a file) are painful.

JavaScript isn't especially well suited to some of these needs. Code organization and the ability to keep server side code modular are especially large problems. Code organization needs generally conflict with minimizing the number of files sucked down. And so on.

The dark horse here is actually item 1, modularity. The moment you start mixing your AJAX with any extensive widgetization it comes to bite you HARD. The livequery paradigm is one way people try to solve this, but that has some undesirable traits, and it leaves large portions of the issue unresolved. The largest part of the modularity problem is ensuring that the proper files are available when needed, but no earlier (We don't want to suck down everything we have, just because an ajax request might return something that needs it.) In the end, for any sort of complex application, a script loader becomes a highly desirable tool. With a good script loader you can ensure that all necessary files are available, while guaranteeing that each file is only loaded a single time (important, since double loading could create bugs). A script loader also opens possibilities for organization of code across separate files, because the files themselves can become responsible for the inclusion of their own external dependencies (Like a WYSIWYG editor, which might require a document range abstraction layer, a json encoder, a gallery plugin, and a cookier plugin).

So, assuming that we use a script loader, take a look back at the server. A request comes in, and needs to return something: let's say a complex form with some custom widgets. The view helpers each build a bit of markup for their widgets. Part of the widget markup is a script element that a) uses $.include (our script loader) to guarantee that the required resources are present, and b) uses $(document).ready(function(){...}) to perform any necessary jQuery operations on the newly created widget, once all the resources are known to be present. The desire is for this widget markup to always works exactly the same way, regardless of whether it was used in the initial page load, or in an AJAX request. If we can do that, the other problems are resolved. The relevant script files never have to be included in a large header monolith, so the initial page load is snappy, and the server side code is clean an modular. The cache value is maximized, no script build phase is needed for development, there is no large wasteful collection of livequery declarations because "we need this sometimes". In order for this bit of magic to work though, the $(document).ready() bits in the response have to be able to work AFTER the ready event has already fired once.

The nuance here is that in the mind of the typical developer, $(document).ready() doesn't actually mean "do this when the document has fired it's on load event". The native load event is such a mess, nobody wants to think about it anymore. That's why jQuery wraps it up in a neat little package. Now we just dump everything in $(document).ready(), and when we do that, we mean "do this as soon as it is safe to run my stuff." The fact that the server responded with new script requirements that have not been loaded, means that it is no longer "ready" or "safe" to execute new scripts, until after it resolves those requirements. The script loader calls $.holdReady(true), just as it does when loading scripts during the page load. The only difference now is that it was an AJAX request, not a page load, but again, the developer doesn't want to have to care. The intent is still the same: "do this stuff whenever it is safe". The expectation is that execution of any $(document).ready() blocks will always be delayed as appropriate. Once the requirements are loaded, execution continues.

This change makes robust script loaders possible, and clears the path for web development paradigms that blur the lines between AJAX and page loads (making the ajaxification of previously static web apps almost trivial.) Without this, any script loader is crippled, because it can't be safely and easily used with AJAX (a major use case). The addition of holdReady() in 1.6 is a major step in the right direction, and this patch continues that by moving it into the AJAX realm.

src/core.js Outdated
// The readyList is (currently) a simplified version of Deferred, and
// has no support for "rejected"
if (readyList && (readyList.isResolved() /* || readyList.isRejected() */))
{

This comment has been minimized.

Copy link
@rwaldron

rwaldron May 6, 2011

Member

Opening brace should be on previous line.

src/core.js Outdated
//
// The readyList is (currently) a simplified version of Deferred, and
// has no support for "rejected"
if (readyList && (readyList.isResolved() /* || readyList.isRejected() */))

This comment has been minimized.

Copy link
@rwaldron

rwaldron May 6, 2011

Member

Watch the whitespace... should be: if ( readyList && (readyList.isResolved() ... )

@jaubourg

This comment has been minimized.

Copy link
Member

commented Jul 17, 2011

The argumentation pro holdReady are so wrong on so many levels.

this breaks code independance

There is nothing modular about having a script loader delaying the ready event: on the contrary, you give any module in your application the means to derail the semantics of the dom ready event and take the risk of breaking other portions of your app relying on said event. In your very sample module, if the ajax request fails, then all modules that rely on dom readyness and are loaded after said module (or even before if dom readyness hasn't been notified yet) will just plain stop working. Now that's modularity for you!

That's how dangerous, inconsistent and pointless this "feature" is. It makes non-dependant modules loading order important while it shouldn't be: you don't always load interdependant modules, sometimes you do have separate and independant portions in your app (at least if you're not doing it wrong). If some remote resource is temporarily unavailable, say the Twitter Data API you only use for a little tweeting widget in the sidebar, do you really want your page as a whole to become unusable because no dom readyness bound function will be called? Is this really the kind of approach we want to promote?

we're breaking jQuery for "convenience", promoting bad practice in the process

Having a bunch of "master" scripts that will block any other module from being loaded should be done within the script loaders themselves. Let them provide a means to add a "global" script and not load and/or execute modules before those "master" scripts are loaded. Is it so hard to code that we need to break jQuery for this? Why should other code in the page that do not make use of the script loader be penalized or plain broken to save a few bytes in the script loader?

Beside, how do I go about making jQuery itself a global include, seeing as I obviously don't have holdReady available at that point? Make an incantation? Nope, you have to use a script tag for this, just as you should for any global script in your app. If you truly want a script to become "part of the environment" (like the script loader itself btw), then that's the way to go. It's easy enough to check script tags in your pages/templates server-side when running your build script that will deliver this fancy all-in-one-file minified js.

Even worse, how can one promote "global" scripts includes as "more modular" or "better organized". Take nodejs, for instance: in every single js file, you have to require all the libs you use in your file. Nobody's complaining about it because it actually makes sense. Global includes are frown upon in any environment I know of and for good reason (they're only available using command-line arguments for the compilers of all languages I used so far, that should tell people something).

Having to specify all you dependencies for a module is not an inconvenience, it's what makes your system truly modular in the first place: you can take your module as is and drop it into any other app/page and it'll just work. If you use "global includes", then you have to copy parts of the environment configuration with it. Talk about maintenance hell.

it makes jQuery's dom readyness notification unreliable

The dom ready event has specific semantics and is not some kind of synchronization utility to be meddled with just because it's convenient to a niche. I'm appalled enough that we have holdReady in the first place... but that we try and break things even more by making it work post dom readyness is beyond me. This has bad practice painted all over the place for reasons I already explained before.

With holdReady in place, I, as a plugin/app developper cannot trust jQuery to properly notify dom readyness. So, in short, I'll duplicate the dom readyness logic in my own code and never use the $( fn ) signature ever again since any third party can meddle with its behaviour without my knowledge. We're talking self-deprecation here.

you can easily join one or several ajax requests with dom readyness

I also don't understand why some people keep on implying it's difficult to sync on ajax requests and dom readyness, all you need is a dom readyness Promise and a construct as follows:

$.when( $.domReadyPromise, $.ajax(...) ).then(function() {
    // your code here
});

Funily enough, even if jQuery doesn't provide domReadyPromise, you can create it pretty easily:

$.domReadyPromise = $.Deferred(function( defer ) {
    $( defer.resolve );
});

This solution doesn't meddle with the dom ready event and, as a consequence, doesn't spit all over any other code in your application: a problematic ajax request won't break surrounding code/widgets/plugins.

@johncrenshaw

This comment has been minimized.

Copy link
Author

commented Jul 20, 2011

@jauborg, This really isn't the place to start a fight over whether holdReady() itself is an acceptable feature. holdReady is here, and there are a handful of very important use cases for it. Before holdReady was added, it really wasn't possible to write a decent script loader without hacking the core. (By "decent" I mean one that would allow you to replace every script tag with a call to the script loader, and have everything continue to work like it did before.)

Some quick thoughts on some of your specific complaints:

Code Independence: In a vanilla web page everything already has to wait for every script file to be sucked down and processed, regardless of which snippets require which scripts. This isn't any different.

Nothing modular about...: Modularity comes (in part) from being able to delay loading of secondary scripts until they are actually needed, avoiding minified monoliths. The modularity empowered by this is on the server side, not the client side.

Failed AJAX Request example: This is a bug in your theoretical code, not a problem with the holdReady concept. Correctly written code would use the completed and/or success+error callback(s) to clear the hold. Additionally, someone would have to be soft in the head to hold the ready event just because they are waiting for data from Twitter. That's not what this is for.

"Let [the script loaders] provide a means to add a "global" script": This isn't DRY. Any time you are waiting for the document to have been loaded, you pretty much need to have assurances that the scripts are ready. The generic dom ready event was originally designed to give this assurance, holdReady allows script loaders to continue to offer that assurance, even though the internal dom ready event hangs you out to dry when a script loader is used.

"you should [use a script tag] for any global script in your app": Um. Wow. You really have no idea why a script loader would ever be needed, do you? I'm not entirely sure how to respond to this. Do you do server side development? PHP? Imagine what it would be like to develop a complex application if PHP didn't have an include or require, or if include/require didn't wait for the file to be included before continuing execution.

"fancy all-in-one-file minified js": I reject the fancy all-in-one minified js. Although this is better than serially loading individual files, it is far from ideal. You are delaying the first page load to suck down every drop of script that the application will ever have to use, even though 90% of it won't get used at all (or at least not until much later). Complex systems will have worse page load times site wide due to the massive amount of script that has to be processed on every page load, even though it isn't needed. A good script loader offers much better alternatives.

"it makes jQuery's dom readyness notification unreliable": It never was "reliable". If you use $(fn) after dom ready has fired, your function will be called, even though dom ready is not firing at that moment. If you really need the dom ready event, bind directly to the dom ready event at the low level. It is highly unlikely that you will ever actually need this, but if you do, you have options.

"any third party can meddle with its behaviour without my knowledge": Not every developer is a raging idiot, and if they are, you don't want their code on your site for reasons that go far beyond whether they abused holdReady. If you are really that worried about it, you could add delete $.holdReady; to your code.

"you can easily join one or several ajax requests with dom readyness": Your proposed code doesn't solve remotely the same problem. Look at this again after you start lusting for a good script loader, and I expect you'll see what the real issue is.

@rwaldron

This comment has been minimized.

Copy link
Member

commented Jul 20, 2011

Can you re-write that with less html and more markdown?

@johncrenshaw

This comment has been minimized.

Copy link
Author

commented Jul 20, 2011

I used the markdown. Looks like a new bug in the system. I think someone probably reversed the html escaping and markdown conversion functions.Trying to figure out a workaround..

EDIT: I figured it out. I used the word "script" in the comment with an angle bracket on the left. Perfectly valid, but something clearly didn't like it and aggressively encoded for security reasons.

@johncrenshaw

This comment has been minimized.

Copy link
Author

commented Jul 20, 2011

Can't figure out a workaround. Whenever github fixes the bug I'll re-submit.

@rwaldron

This comment has been minimized.

Copy link
Member

commented Jul 20, 2011

Click the "edit" button that appears when you mouse over the text body? Furthermore, less arguing and more fixing the issues I pointed out in your patch. Also, for any sort of consideration this will need a test, take a look at the test in test/readywait.html

@johncrenshaw

This comment has been minimized.

Copy link
Author

commented Jul 20, 2011

I already tried edit; no go.

I saw that you added a whitespace correction, but I don't see that you pointed out any "issues" that need fixing. Can you clarify what is wanted?

I'll add a unit test. How do I add the test to the pull request?

@rwaldron

This comment has been minimized.

Copy link
Member

commented Jul 20, 2011

Those are the "issues".

All you need to do is write the test, commit it, push it to your branch and the pull request will automatically be updated.

@rwaldron

This comment has been minimized.

Copy link
Member

commented Jul 20, 2011

... I just noticed that you're not using a branch. In the future, please write patches on branches that correspond to ticket numbers. Which brings me to another point - where is the ticket for this?

@johncrenshaw

This comment has been minimized.

Copy link
Author

commented Jul 20, 2011

Ticket is #9389. I've committed a unit test. I had to clean up the old readywait test just a little at the same time because it wasn't sufficient for running multiple tests on the page.

@dmethvin

This comment has been minimized.

Copy link
Member

commented Jul 20, 2011

I'm not a fan of this change, similar concerns as @jaubourg. The contract for .ready() atm says that once a document is ready, it stays ready. This changes the contract.

Script loaders and other functions that need further contracts or events can collaborate to create them outside jQuery. Is there any infrastructure missing to allow someone to do this externally?

@rwaldron

This comment has been minimized.

Copy link
Member

commented Jul 20, 2011

@johncrenshaw thanks for updating those review points... In my experience @jaubourg has always been on point with both the goals of the jQuery project and the means of reaching them. While I completely agree with his points, I did some further independent research to seek out more information about common patterns of script loading in the context of well known implementations with proven use cases. The current jQuery.holdReady() and jQuery.readyWait APIs were developed in concert with James Burke and his RequireJS needs, additionally, Kyle Simpson's LABjs doesn't demand additional library APIs and still allows for programmatic dependency management.

-1

@jaubourg jaubourg closed this Jul 20, 2011

@jaubourg

This comment has been minimized.

Copy link
Member

commented Jul 20, 2011

This really isn't the place to start a fight over whether holdReady() itself is an acceptable feature.

Yes it is, especially given you're attempting to turn it into something even worse than what it is now.

In a vanilla web page everything already has to wait for every script file to be sucked down and processed, regardless of which snippets require which scripts. This isn't any different.

Wrong, you can use async or defer on your script tags. But that's beside the point: the gist of your argument is pro script loader not pro holdReady.

Modularity comes (in part) from being able to delay loading of secondary scripts until they are actually needed, avoiding minified monoliths. The modularity empowered by this is on the server side, not the client side.

No Modularity is about code independance and re-usability, and global includes break both. When you need to make sure several modules are included using a nice shorthand then you create a new module that does all said includes then include this module... just like you would server-side. This makes it easy and straight-forward to track down dependencies when you need to use the same module elsewhere.

This is a bug in your theoretical code, not a problem with the holdReady concept. Correctly written code would use the completed and/or success+error callback(s) to clear the hold. Additionally, someone would have to be soft in the head to hold the ready event just because they are waiting for data from Twitter. That's not what this is for.

No it was a bug in your theoretical code, that's the thing here. Your description of the code clearly states "when it is loaded": please read yourself careful. This kind of coding error happens far too often and is to be expected with something as haskish as holdReady.

As for the Twitter example, as contrived as it may seem, if you get into the habit of adding includes globally and use holdReady together with dom readyness as your synchronization means, then you will end up with problems like this faster than you can say "soft in the head". Some of the bugs we encounter in jQuery itself are quite dumb, yet only occur is such specific conditions they were nearly impossible to predict. Let something like holdReady lose in the API and see how it goes.

When I see people doing it wrong with some very straight-forward things, I don't feel like putting a gun in their hands. Also, with a non-trivial application, with more than a single module and developper, tracking the problem will be a nightmare: it won't throw an exception, it won't notify anything, it just won't do a thing.

I do appreciate you saying "That's not what it is for" because that's exactly my point regarding $( fn ) not being for anything else than dom readyness detection. Maybe you're starting to appreciate what I'm talking about here?

This isn't DRY. Any time you are waiting for the document to have been loaded, you pretty much need to have assurances that the scripts are ready. The generic dom ready event was originally designed to give this assurance, holdReady allows script loaders to continue to offer that assurance, even though the internal dom ready event hangs you out to dry when a script loader is used.

Don't Repeat Yourself doesn't mean "Patch Someone Else's Work To Death Until It Does What I Want It To" nor "Dump What You Don't Wanna Code On Someone Else's Shoulders". And you still confuse dom readyness and page load events. The dom ready event will fire as soon as the dom is ready for manipulation not when everything is loaded and processed... hence why you can use "async" on script tags, just like the latest snippets from google analytics do (in order not to derail/delay the dom readyness event hint hint).

Um. Wow. You really have no idea why a script loader would ever be needed, do you? I'm not entirely sure how to respond to this. Do you do server side development? PHP? Imagine what it would be like to develop a complex application if PHP didn't have an include or require, or if include/require didn't wait for the file to be included before continuing execution.

Again, you're missing the point and arguing pro script loader, not pro holdReady. If you want some scripts to delay the dom readyness event then you use a script tag without async nor defer. It's easy enough to code a solution for this server-side (and that's coming from someone who does a lot of server-side coding, in PHP and node): use a proper templating system.

Of course, the real issue comes right in your face when you choose this road: you have two sets of dependencies per module, one of which is not in js/client-side. Re-using a module becomes an excercise in information retrieval. This is sadly the very problem you intend to bring client-side with global includes (two sets of dependencies), except you shadow the issue and make it impossible to properly track said dependencies and make script loader agnostic code suffer your hastyness. That's actually where script loaders should help: remove global includes altogether and make dependency management a non-issue.

Let's look at how one would implement an asynchronous require server-side just to see how it would look.

Would you expose a global method to delay some kind of global event? Of course not, because it wouldn't make sense, would break existing code or, worse, necessitate that you rewrite all your existing modules (which is exactly what you're advocating for client-side here, whether you realize it or not).

No, the solution is very simple indeed: you keep track of asynchronous requires inside of the module code itself and don't consider the main module as loaded as long as those internal dependencies are pending:

// mainModule.js
requireAsync( "myFirstModule", function( myFirstModule ) {
    if ( myFirstModule.someCondition ) {
       requireAsync( "mySecondModule", function( mySecondModule ) {
           // Expose stuff
       }
    }
    // Expose stuff
});

// myApp.js
requireAsync( "mainModule", function( mainModule ) {
    // myFirstModule is loaded
    // and mySecondModule too if needed
});

If you ever need to do something asynchronous that is not about requiring a module (an ajax request for instance), than you provide an hold facility that is local and specific to the module itself:

// holdModule.js
requireAsync( "myFirstModule", function( myFirstModule ) {
    // Expose stuff
    require.hold(function( releaseHold ) {
       somethingAsync( param1, param2, function() {
           // Expose stuff
           releaseHold();
       });
    })
});

// myApp.js
requireAsync( "holdModule", function( mainModule ) {
    // myFirstModule is loaded
    // somethingAsync was performed
});

If you never call the releaseHold callback, then you only block the module itself and code that depends on it, not the entire application.

If your script loader doesn't provide such a facility, then you have a feature enhancement request to open in the script loader's bug tracker. You don't hack poor jQuery away just because it's "convenient" and we're softies that like to please (and that we are).

I reject the fancy all-in-one minified js. Although this is better than serially loading individual files, it is far from ideal. You are delaying the first page load to suck down every drop of script that the application will ever have to use, even though 90% of it won't get used at all (or at least not until much later). Complex systems will have worse page load times site wide due to the massive amount of script that has to be processed on every page load, even though it isn't needed. A good script loader offers much better alternatives.

See? We can agree on something. Note that the requireAsync/require.hold solution I talked about in the previous question makes it easier for a server-side builder to parse and determine what needs to be loaded right away and what doesn't. Though the parser is non-trivial, mind you.

It never was "reliable". If you use $(fn) after dom ready has fired, your function will be called, even though dom ready is not firing at that moment. If you really need the dom ready event, bind directly to the dom ready event at the low level. It is highly unlikely that you will ever actually need this, but if you do, you have options.

Confusion again. It was. We have the dom ready event... then we have the dom readyness facility in jQuery: these are not the same. As of 1.5, $( fn ) is implemented using a Deferred internally and contract is this deferred will be resolved as soon as possible, that is as soon as the dom ready event is fired.

holdReady will break this and, even worse, make it possible for "as soon as possible" to become "never" much too easily.

Not every developer is a raging idiot, and if they are, you don't want their code on your site for reasons that go far beyond whether they abused holdReady. If you are really that worried about it, you could add delete $.holdReady; to your code.

I am a raging idiot, you are a raging idiot. Hell, we're all bloody morons when it comes to coding. And supposing there were "smart" coders in this world, everyone does not have the luxury to choose who or what they work with.

Your proposed code doesn't solve remotely the same problem. Look at this again after you start lusting for a good script loader, and I expect you'll see what the real issue is.

I use script loaders (labJS, requireJS or yepnope, depending on the project's specific needs) daily and I even wrote two (well the second one I'm writing/redesigning right now). I wrote them to understand what the limitations were, especially client-side, and to provide some facilities I needed in real-life applications.

I can tell you it gave me quite a good perspective on them. Perspective is key here and is what you're lacking in my humble opinion.

As soon as I investigated what it would take to make an asynchronous module/dependency manager, the first thing I implemented was a mean to wait for internal dependencies and/or define modules as a collection of dependencies (even full fledged dependency expressions in dominoes). If you have these facilities in a script loader (and, to my knownledge, most provide something related to a certain extend), then you do have everything you need.

If you still feel like hacking into jQuery's dom readyness system then you're obviously doing it very very wrong:

  • it makes jQuery a "system" dependency, so you are forced to put jQuery in a non-async script tag in your HTML code: what if a page does not need jQuery? You got it, you need to deal with the problem server-side which is exactly the thing you frown upon,
  • you refuse or don't know how to use some advanced facilities in your script loader, worse, your script loader doesn't provide the tools you need for a specific application: change of script loader (they're not all done for the same purpose: some are plain JS loaders, others dependency managers and others full-fledged modularization systems).

Food for thought: what if the module you load doesn't make any dom manipulation (like underscore)? What is the meaning of this module waiting for the dom to be ready? None. That's how "sound" this whole mess of an idea holdReady actually is.

@johncrenshaw

This comment has been minimized.

Copy link
Author

commented Jul 20, 2011

@dmethvin, I understand your concern with the possibility of not staying ready. I guess that is sort of my point. The developer has been made two conflicting promises. The first is that "inside $.ready, all scripts are loaded" (this is implicit in the dom ready event, or enforced via $.holdReady by a compatible script loader). The second is that "$.ready stays ready", which is part of the purpose of the abstraction. This is fine until $.require gets called later; then you have a conflict. Do you continue to run $.ready callbacks, even though some scripts are now not loaded? Or do you wait for the new scripts to load before continuing? My vote is for the latter, because it honors the spirit of both needs. The developer who uses $.ready(...) has already explicitly decided to run the script later if needed, to ensure that everything is ready before the script runs. The developer still has a guarantee that the script will always run, and also has the guarantee that any previously included scripts were loaded.

@rwldrn, The need for pausing the ready event after a completed load isn't obvious until you consider the server side. You mentioned seeking "well known implementations with proven use cases", so I'll use Zend Framework to describe the situation.

  1. Consider a Zend Framework based app
  2. Include jQuery (but not jQuery UI) on the page
  3. $.load a view that uses one of the jQuery view helpers
  4. It won't work.

These helpers manage their own dependencies, and will attempt to add the needed script, but it doesn't work when the request is AJAX based (even if a script loader is used, because the Zend Framework code, like most similar code, is using $.ready for it's "all scripts are loaded" merits, and that isn't honored for asynchronously loaded content). This is a recurring problem for server side development of applications in AJAX heavy systems, and presents a serious barrier to AJAX, especially in existing code.

@jaubourg, I'm pro this patch, which mostly makes sense relative to script loaders used in content returned via AJAX; I'm not going to fight with you about holdReady itself.

@johncrenshaw

This comment has been minimized.

Copy link
Author

commented Jul 20, 2011

I'm a little bothered that jaubourg has closed this request. Was this deliberate, or an accident? If it is rejected by the team that's fine, but I don't like the idea of it getting closed unilaterally by someone who obviously has an axe to grind.

@dmethvin

This comment has been minimized.

Copy link
Member

commented Jul 20, 2011

The developer has been made two conflicting promises. The first is that "inside $.ready, all scripts are loaded" (this is implicit in the dom ready event, or enforced via $.holdReady by a compatible script loader). The second is that "$.ready stays ready", which is part of the purpose of the abstraction. This is fine until $.require gets called later; then you have a conflict. Do you continue to run $.ready callbacks, even though some scripts are now not loaded? Or do you wait for the new scripts to load before continuing?

That's a tortured argument. The ready says that the DOM has loaded. None of the code is clairvoyant, it can't know whether you might add new scripts. I think we all agree that ready should not fire if you add new HTML to the DOM after the document is ready, right? The $.require method is not part of jQuery, it should create its own conventions for including scripts and running post-include code after the document is ready.

I'm a little bothered that jaubourg has closed this request. Was this deliberate, or an accident?

I don't know; I have definitely closed pull requests accidentally because the "Comment and Close" button is bigger. However, I would be against merging this patch as well, and haven't heard anyone on the team give it an upvote.

@rwaldron

This comment has been minimized.

Copy link
Member

commented Jul 20, 2011

@johncrenshaw

If it is rejected by the team that's fine, but I don't like the idea of it getting closed unilaterally by someone who obviously has an axe to grind.

It's not @jaubourg's axe to grind - 3 contributors and 2 committers are telling you that the motion is rejected. It's also not personal, it's about what is right and what is wrong for the library as a core piece of code used by >24 million websites.

@dmethvin

This comment has been minimized.

Copy link
Member

commented Sep 1, 2011

Since this didn't get into the 1.7 feature pile, I've marked the ticket for discussion during the 1.8 cycle.

@lock lock bot locked as resolved and limited conversation to collaborators Jan 21, 2019

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
You can’t perform that action at this time.