【问题标题】:Execute javascript after page load is complete [duplicate]页面加载完成后执行javascript [重复]
【发布时间】:2015-01-13 07:05:10
【问题描述】:

我有一个 html 页面,其中包含一些预渲染的内容和一些尚未渲染的内容。我想立即显示预渲染的内容,然后开始渲染其余的内容。 我没有使用 jQuery

参见下面的 sn-p。我尝试了各种方法,包括在结束正文标记之前注入我的脚本,并提供我的脚本来填充 DOM 作为对window.onloaddocument.body.onloaddocument.addEventListener('DOMContentLoaded') 的回调。在任何情况下,页面都不会显示预渲染的内容,直到其余内容被渲染。

<html><head></head>
  <body>
    <header>What it is, my doge?</header>
    <div id="main"></div>
    <script>
      var main = document.getElementById('main');
      for (var i = 0; i < 500; i++)
        main.innerText += new Date();
    </script>
  </body>
</html>

<html><head></head>
  <body>
    <header>What it is, my doge?</header>
    <div id="main"></div>
    <script>
      var main = document.getElementById('main');
      document.body.onload = function() {
        for (var i = 0; i < 500; i++)
          main.innerText += new Date();
      };
    </script>
  </body>
</html>

<html><head></head>
      <body>
        <header>What it is, my doge?</header>
        <div id="main"></div>
        <script>
          var main = document.getElementById('main');
          window.onload = function() {
            for (var i = 0; i < 500; i++)
              main.innerText += new Date();
          };
        </script>
      </body>
    </html>

<html><head></head>
      <body>
        <header>What it is, my doge?</header>
        <div id="main"></div>
        <script>
          var main = document.getElementById('main');
          document.addEventListener('DOMContentLoaded', function() {
            for (var i = 0; i < 500; i++)
              main.innerText += new Date();
          });
        </script>
      </body>
    </html>

一个有效的案例是window.setTimeout,超时时间为0。但是,这只是将功能推迟到无事可做。这是最佳做法吗?

<html><head></head>
<body>
    <header>What it is, my doge?</header>
    <div id="main"></div>
    <script>
      var main = document.getElementById('main');
      window.setTimeout(function() {
        for (var i = 0; i < 500; i++)
          main.innerText += new Date();
      }, 0);
    </script>
</body>
</html>

【问题讨论】:

  • 1) 我们需要这里的代码。 2)您的描述与小提琴不符。 3) window.onload 将在所有内容加载完毕后触发。你需要做的就是把你的电话放在&lt;/body&gt;标签之前
  • 小提琴正是你所描述的一个例子,它显然不起作用。
  • @MatthewJamesDavis 您的未渲染内容是如何渲染的?
  • 任意。可能通过剔除或通过 DOM API 附加文档片段。
  • 注意:setTimeout(function(){}, 0) 方法在 FireFox 中似乎不起作用。它需要约 50-100 毫秒的超时时间。

标签: javascript html dom


【解决方案1】:

最佳实践而言,没有。就良好常见可接受的做法而言,有一些。你中了一个:

setTimeout(function() { }, 1);

在这种情况下,函数在所有其他内联处理结束后在the browser's minimum timeout period 内执行。

同样,如果您想确保您的函数在某些条件为真后不久运行,请使用间隔:

var readyCheck = setInterval(function() {
  if (readyCondition) {
    /* do stuff */
    clearInterval(readyCheck);
  }
}, 1);

我一直在自己的工作中使用类似但更通用的解决方案。我在标题中定义了一个辅助函数:

var upon = function(test, fn) {
    if (typeof(test) == 'function' && test()) {
        fn();
    } else if (typeof(test) == 'string' && window[test]) {
        fn();
    } else {
        setTimeout(function() { upon(test, fn); }, 50);
    }
}; // upon()

...当依赖关系解决时,我会触发其他功能:

upon(function() { return MyNS.Thingy; }, function() {
  //  stuff that depends on MyNS.Thingy
});

upon(function() { return document.readyState == 'complete';}, function() {
  // stuff that depends on a fully rendered document
});

或者,如果您想要更权威的良好实践,请遵循 Google 的示例。创建一个外部 async 脚本并将其注入到您的第一个标头 script 之前:

var s = document.createElement('script'); s.type = 'text/javascript'; s.async = true;
s.src = '/path/to/script.js';
var header_scripts = document.getElementsByTagName('script')[0];
header_scripts.parentNode.insertBefore(s, header_scripts);

Google 的解决方案理论上适用于所有浏览器(IE

如果您想要一个权威的common实践,请查看 jQuery 的onready 解决方案的来源。

【讨论】:

  • 知道为什么谷歌建议你建议你注入它而不是包含它吗?
  • @MatthewJamesDavis Two reasons 我知道。这里似乎只有一个相关:某些浏览器不支持async 属性。
  • @MatthewJamesDavis 在此处查看对async 的浏览器支持:developer.mozilla.org/en-US/docs/Web/HTML/Element/…
  • 我会在你对未来求职者的回答中包含异步
  • @svidgen:我可以直接使用带有 aync 属性的标题部分中的脚本标记来代替脚本注入吗? (如下所示)&lt;script async src="/path/to/script.js" type="text/javascript"&gt;&lt;/script&gt;
【解决方案2】:

根据您的浏览器要求,您可以使用async 标签并在内容加载后导入您的脚本。这可能与setTimeout(func, 0) 完成相同的事情,但也许它不那么hacky。

http://plnkr.co/edit/7DlNWNHnyX5s6UE8AFiU?p=preview

html:

...
<body>
  <h1 id="main">Hello Plunker!</h1>
  <script async src="script.js"></script>
</body>
...

script.js:

for(var i=0; i<500; ++i) {
  document.getElementById('main').innerText += new Date();
}

【讨论】:

  • 它的 hacky 少了很多。 setTimeout 方法说“嘿,在你下载这个脚本时停止一切,然后完成你要做的任何事情,然后执行脚本”,其中 async 说“完成所有事情,然后在准备好时执行脚本”
【解决方案3】:

我以前用过这个效果:

var everythingLoaded = setInterval(function() {
  if (/loaded|complete/.test(document.readyState)) {
    clearInterval(everythingLoaded);
    init(); // this is the function that gets called when everything is loaded
  }
}, 10);

【讨论】:

    【解决方案4】:

    我认为您想要做的是在标签上使用 onload 事件。 这边首先是“这是什么,我的总督?”处理 javascript 时将出现消息。

    我还在循环内设置了一个超时,这样你就可以更好地看到正在添加的行。

    <html>
        <head>
            <script>
                myFunction = function() {
                    for (var i = 1000; i > 0; i--) {
                        setTimeout(function() {
                            main.innerText += new Date();
                        }, 100);
                    }
                };
            </script>
        </head>
    
        <body onload="myFunction()">
            <header>What it is, my doge?</header>
            <div id="main"></div>
        </body>
    </html>
    

    【讨论】:

    • 欣赏答案。然而,这并不像我发布的想法那样最佳,在回调之外设置一个对 window.setTimeout 的调用,超时为 0,这要快得多。
    猜你喜欢
    • 2012-08-09
    • 1970-01-01
    • 2016-08-21
    • 2013-03-28
    • 2022-12-19
    • 2013-06-02
    • 2015-01-28
    • 1970-01-01
    • 2014-11-21
    相关资源
    最近更新 更多