最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

asynchronous - Javascript: Run function when page has finished loading, script is loading async - Stack Overflow

programmeradmin1浏览0评论

I can't find a reliable way to find when the page has finished loading. My current code looks like this:

function pageLoaded(callback) {
    function pleted() {
        document.removeEventListener('DOMContentLoaded', pleted);
        callback();
    }

    if (document.readyState === 'plete') {
        callback();
    } else {
        document.addEventListener('DOMContentLoaded', pleted);
    }
}

The issue is that DOMContentLoaded gets fired before document.readyState gets set to 'plete' which means that the callback never gets called.

When my function runs DOMContentLoaded has already been fired but document.readyState === 'interactive'. However I don't think I can run my callback when document.readyState === 'interactive' due to these possible issues.

Unfortunately I don't think I can make a demo due to the use of async. Also this doesn't happen 100% of the time but it seems to happen always when I do a hard reload (I assume something to do with caching).

Note that I'm loading in my script like this in my <head>:

<script src="script.js" async></script>

I can't find a reliable way to find when the page has finished loading. My current code looks like this:

function pageLoaded(callback) {
    function pleted() {
        document.removeEventListener('DOMContentLoaded', pleted);
        callback();
    }

    if (document.readyState === 'plete') {
        callback();
    } else {
        document.addEventListener('DOMContentLoaded', pleted);
    }
}

The issue is that DOMContentLoaded gets fired before document.readyState gets set to 'plete' which means that the callback never gets called.

When my function runs DOMContentLoaded has already been fired but document.readyState === 'interactive'. However I don't think I can run my callback when document.readyState === 'interactive' due to these possible issues.

Unfortunately I don't think I can make a demo due to the use of async. Also this doesn't happen 100% of the time but it seems to happen always when I do a hard reload (I assume something to do with caching).

Note that I'm loading in my script like this in my <head>:

<script src="script.js" async></script>
Share Improve this question edited Jul 9, 2015 at 22:36 joshhunt asked Jul 9, 2015 at 4:19 joshhuntjoshhunt 5,3557 gold badges41 silver badges60 bronze badges 14
  • … don’t use async? – Ry- Commented Jul 9, 2015 at 4:24
  • 2 A fully built function to do this is here: stackoverflow./questions/9899372/… – jfriend00 Commented Jul 9, 2015 at 4:26
  • @minitech but then it blocks rendering? – joshhunt Commented Jul 9, 2015 at 4:28
  • It seems to me that the javascript loader solves the problem. LABjs? – stdob-- Commented Jul 9, 2015 at 4:33
  • @jfriend00 Thanks I'll take a look and make sure it works with async. I had a look at jQuery's current code but I don't really understand it, it looks like they are using promises? github./jquery/jquery/blob/… – joshhunt Commented Jul 9, 2015 at 4:33
 |  Show 9 more ments

2 Answers 2

Reset to default 6

I couldn't find much useful information on the subject so I decided to do some tests. I set up a Node server that would:

  1. Send the start of an html document
  2. Wait 5 seconds
  3. Send the rest of the html which includes an image

I then recorded the status of document.ready and DOMContentLoaded at each stage. My code:

var http = require('http');

var server = http.createServer(function(req, res) {
    // Send the first part of the html
    res.writeHead(200, {'Content-Type': 'text/html'});
    res.write(
        '<!doctype html>' +
            '<html lang="en">' +
                '<head>' +
                    '<meta charset="utf-8">' +
                    '<meta http-equiv="x-ua-patible" content="ie=edge">' +
                    '<title>JS Ready Test</title>' +
                    '<meta name="description" content="">' +
                    '<meta name="viewport" content="width=device-width, initial-scale=1">' +

                    '<script>' +
                        'console.log(document.readyState);' +

                        'document.onreadystatechange = function () {' +
                            'console.log(document.readyState);' +
                        '};' +

                        'document.addEventListener("DOMContentLoaded", function() {' +
                            'console.log("DOMContentLoaded");' +
                        '});' +
                    '</script>' +
                '</head>' +
                '<body>');
    // Send a bunch of blank spaces so that the browser will load the buffer, if the buffer is too small the browser will wait for more data
    var str = 'Start';
    for (var i = 0; i < 2000; i++){
      str += ' ';
    }
    res.write(str);

    // Wait 5 seconds and send the rest of the data
    setTimeout(function () {
        res.write('Finish<img src="https://upload.wikimedia/wikipedia/mons/3/3d/LARGE_elevation.jpg"></body></html>');
        res.end();
    }, 5000);
});

// Listen on port 3000
server.listen(3000);

Results from my tests

First Buffer
Chrome (v43) / FF (v39) / IE11: document.ready === 'loading'
IE9 / IE10: document.ready === 'interactive'

Final buffer
Chrome / FF / IE11: document.ready === 'interactive', DOMContentLoaded called
IE9 / IE10: No change in document.ready, DOMContentLoaded called

Sub-resources finish loading (in this case the image)
Chrome / FF / IE11: document.ready === 'plete'
IE9 / IE10: document.ready === 'plete'

As you can see IE9 & IE10 set document.ready === 'interactive' too early.

Some possible solutions

1. Ignore IE9 / IE10

if (document.readyState === 'interactive' || document.readyState === 'plete') {
    callback();
} else {
    document.addEventListener('DOMContentLoaded', callback);
}

2. Add the DOMContentLoaded in the <head> of your document outside of your async script. This ensures that it will be attached before it is called.

// In <head>
<script>
    var pageLoaded = false;

    document.addEventListener('DOMContentLoaded', function() {
        pageLoaded = true;
    });
</script>

// In script.js
if (pageLoaded) {
    callback();
} else  {
    document.addEventListener('DOMContentLoaded', callback);
}

3. Fallback to the load event on `window.

if (document.readyState === 'plete') {
    callback();
} else {
    // You would need to add a safety so that your functions don't get called twice
    document.addEventListener('DOMContentLoaded', callback);
    window.addEventListener( "load", callback);
}
function pageLoad(callback) {
    if ("function" == typeof callback) {
        if (document.addEventListener) { // Event that fires when the initial HTML document has been pletely loaded and parsed
            document.addEventListener("DOMContentLoaded", callback, false);
        } else if (window.attachEvent) { // For IE 8 and below
            window.attachEvent("onload", callback);
        } else if ("function" == typeof window.onload) { // Event that fires when the page has fully loaded including images / scripts etc
            var o = window.onload;
            window.onload = function() {
                o();
                callback();
            };
        } else {
            window.onload = callback;
        }
    }
}

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论