Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

jqLite "document ready" implementation causes lazy-loaded apps bootstrap to be delayed after window.onload #15690

Open
laurentgoudet opened this issue Feb 8, 2017 · 3 comments

Comments

@laurentgoudet
Copy link

Do you want to request a feature or report a bug?

Report a bug

What is the current behavior?

jqLite current "document ready" implementation uses DOMContentLoaded with window.onload as a fallback.

function jqLiteReady(fn) {
  function trigger() {
    window.document.removeEventListener('DOMContentLoaded', trigger);
    window.removeEventListener('load', trigger);
    fn();
  }

  // check if document is already loaded
  if (window.document.readyState === 'complete') {
    window.setTimeout(fn);
  } else {
    // We can not use jqLite since we are not done loading and jQuery could be loaded later.

    // Works for modern browsers and IE9
    window.document.addEventListener('DOMContentLoaded', trigger);

    // Fallback to window.onload for others
    window.addEventListener('load', trigger);
  }
}

If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem via https://plnkr.co or similar (template: http://plnkr.co/edit/tpl:yBpEi4).

  • Load your code asynchronously (e.g., using SystemJS), to unblock the critical rendering path, and manually bootstrap an Angular app:
angular.element(function() {
    angular.bootstrap(document.getElementById('myApp'), ['myApp']);
}
  • Have something else delay the window.onload event, e.g. a tracking script inserting a pixel into the DOM

  • Because the former code is checking for window.document.readyState === 'complete', the Angular app won't be bootstrapped until after window.onload, potentially causing several seconds of delays.

Unfortunately I can't create a plunker for it as plunker always execute code after the load event.

What is the expected behavior?

According to https://html.spec.whatwg.org/multipage/dom.html#current-document-readiness, document.readyState:

Returns "loading" while the Document is loading, "interactive" once it is finished parsing but still loading sub-resources, and "complete" once it has loaded.

What is the motivation / use case for changing the behavior?

As after DOMContentLoaded the document is interactive, checking for readyState === 'complete' is incorrect and forces asynchronously loaded Angular apps to wait for the - potentially far away - window.onload event.

The jQuery "document ready" implementation itself had a similar bug, which has been fixes in jquery/jquery@dabd5ba. Apparently IE9/IE10 readyState implementation is buggy and one has to rely on document.readyState !== "loading" && !document.documentElement.doScroll instead of readyState === 'interactive'.

Which versions of AngularJS, and which browser / OS are affected by this issue? Did this work in previous versions of AngularJS? Please also test with the latest stable and snapshot (https://code.angularjs.org/snapshot/) versions.

All versions of AngularJS & all browsers

@gkalpak
Copy link
Member

gkalpak commented Feb 8, 2017

Sounds reasonable.
@mgol: Any idea why we aren't following jQuery?

@mgol
Copy link
Member

mgol commented Feb 8, 2017

readyState is buggy in many browsers. jQuery has tried to use it in the past and had to revert. Now it's back in the source with some hacks to exclude IE 9-10 where it's broken but it seems we'll have to revert back in jQuery 3.2.0. See Timmy's comment at: jquery/jquery#3271 (comment)

All that to say, a perfect .ready is impossible. This is a choice between interactive or complete. It pains me to say it, but I think we have to drop interactive. It would be worse to document that jQuery can't be loaded with the defer attribute.

I can't recommend relying on readyState because of that. At the very least I'd at least wait for what the new solution will be in jQuery 3.2.0.

@gkalpak
Copy link
Member

gkalpak commented Feb 8, 2017

😄 Things are never as simple as they may seem (especially when there is more than one browser involved).
Totally, agree we should wait and see what wy jQuery will go.

@gkalpak gkalpak modified the milestones: Ice Box, Purgatory Feb 8, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants