I've read a lot of Stack Exchange questions on that matter (a couple of dozens, I think); unfortunately, they are either primitive and cover slightly different issues, or are badly formatted and unanswered, or answered incorrectly (though some are accepted). I will try to keep my examples as small as possible to illustrate the problem.
Let's take a simplest example:
<!DOCTYPE html>
<head>
<script>
var start = Date.now();
function log(s) { console.log((Date.now()-start), s); }
window.addEventListener('DOMContentLoaded', function() {log('Real DOMContentLoaded');});
</script>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script>
log('jQuery loaded');
$(function() { log('jQuery DOM ready'); });
$(window).load(function() { log('jQuery document loaded'); });
</script>
</head>
<body>
<img src="http://upload.wikimedia.org/wikipedia/commons/3/30/Googlelogo.png">
</body>
The code works as expected, jQuery's DOM ready event fires early:
288 "jQuery loaded"
307 "jQuery DOM ready"
314 "Real DOMContentLoaded"
1376 "jQuery document loaded"
Now let's use require.js:
<!DOCTYPE html>
<head>
<script>
var start = Date.now();
function log(s) { console.log((Date.now()-start), s); }
window.addEventListener('DOMContentLoaded', function() {log('Real DOMContentLoaded');});
</script>
<script src="//cdnjs.cloudflare.com/ajax/libs/require.js/2.1.10/require.min.js"></script>
<script>
require.config({
paths: {
jquery: "//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min"
}
});
require(["jquery"], function($) {
log('jQuery loaded');
$(function() { log('jQuery DOM ready'); });
$(window).load(function() { log('jQuery document loaded'); });
});
</script>
</head>
<body>
<img src="http://upload.wikimedia.org/wikipedia/commons/3/30/Googlelogo.png">
</body>
Suddenly, jQuery's DOM ready event doesn't fire until the document is fully loaded:
297 "Real DOMContentLoaded"
607 "jQuery loaded"
1255 "jQuery DOM ready"
1258 "jQuery document loaded"
Apparently, jQuery misses the browser's DOMContentLoaded event and thus falls back to window.onload to run its own ready event.
Now let's add require.js'es own domReady plugin to the blend:
<!DOCTYPE html>
<head>
<script>
var start = Date.now();
function log(s) { console.log((Date.now()-start), s); }
window.addEventListener('DOMContentLoaded', function() {log('Real DOMContentLoaded');});
</script>
<script src="//cdnjs.cloudflare.com/ajax/libs/require.js/2.1.10/require.min.js"></script>
<script>
require.config({
paths: {
jquery: "//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min",
domReady: "//cdnjs.cloudflare.com/ajax/libs/require-domReady/2.0.1/domReady"
}
});
require(["domReady"], function(domReady) {
log('domReady loaded');
domReady(function() { log('domReady DOM ready'); });
});
require(["jquery"], function($) {
log('jQuery loaded');
$(function() { log('jQuery DOM ready'); });
$(window).load(function() { log('jQuery document loaded'); });
});
</script>
</head>
<body>
<img src="http://upload.wikimedia.org/wikipedia/commons/3/30/Googlelogo.png">
</body>
Unfortunately, it doesn't work any different from jQuery's ready event:
341 "Real DOMContentLoaded"
582 "jQuery loaded"
648 "domReady loaded"
1284 "jQuery DOM ready"
1289 "jQuery document loaded"
1299 "domReady DOM ready"
Is there a proper, beautiful, cross-browser way to attach a DOM ready handler with require.js and jQuery without custom hacks and reinventing the wheel? And what's the point of having require-domReady plugin at all, if it doesn't really work?
I will not mark this as "accepted" since I'm not proud of the solution, but here's what I ended up with, for the record (someone was asking in the comments). I've coded my solution as the domReadyEx
function that I add to jQuery to make it readily available everywhere jQuery is used:
<!DOCTYPE html>
<head>
<script>
var start = Date.now();
function log(s) { console.log((Date.now()-start), s); }
window.addEventListener('DOMContentLoaded', function() {log('Real DOMContentLoaded');});
</script>
<script src="//cdnjs.cloudflare.com/ajax/libs/require.js/2.1.10/require.min.js"></script>
<script>
require.config({
paths: {
jquery: "//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min"
}
});
require(["jquery"], function($) {
log('jQuery loaded');
$.domReadyEx = function(handler) {
// Poor jQuery can't figure it itself if loaded asynchronously and falls back to window.onload which is undesirably late.
if (document.readyState == 'interactive' || document.readyState == 'complete') {
handler();
} else {
$(document).ready(handler);
}
}
$(function() { log('jQuery DOM ready'); });
$(window).load(function() { log('jQuery document loaded'); });
$.domReadyEx(function() { log('jQuery.domReadyEx'); });
});
</script>
</head>
<body>
<img src="http://upload.wikimedia.org/wikipedia/commons/3/30/Googlelogo.png">
</body>
The output:
417 "Real DOMContentLoaded"
516 "jQuery loaded"
517 "jQuery.domReadyEx"
1123 "jQuery DOM ready"
1128 "jQuery document loaded"
I'm pretty sure it's not fully cross-browser, but I don't care about the code working slower in older browsers or IE.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With