页面渲染时js阻塞的解决方法

一般地,一个包含外部样式表文件和外部脚本文件的HTML载入和渲染过程是这样的:

  1. 浏览器下载HTML文件并开始解析DOM。
  2. 遇到样式表文件link[rel=stylesheet]时,将其加入资源文件下载队列,继续解析DOM。
  3. 遇到脚本文件时,暂停DOM解析并立即下载脚本文件。
  4. 下载结束后立即执行脚本,在脚本中可访问当前<script>以上的DOM。
  5. 脚本执行结束,继续解析DOM。
  6. 整个DOM解析完成,触发DOMContentLoaded事件。

什么是阻塞?

  在页面中我们通常会引用外部文件,而浏览器在解析HTML页面是从上到下依次解析、渲染,如果<head>中引用了一个a.js文件,而这个文件很大或者有问题,需要2秒加载,那么浏览器会停止渲染页面(此时是白屏显示,就是页面啥都没有),2秒后加载完成才会继续渲染,这个就是阻塞。

为什么会阻塞?

  因为浏览器不知道a.js中执行了哪些脚本,会对页面造成什么影响,所以浏览器会等js文件下载并执行完成后才继续渲染,如果这个时间过长,会白屏。

解决方法

1、推迟加载(延迟加载)

  如果页面初始的渲染并不依赖于js或者CSS可以用推迟加载,就是最后在加载js和css,把引用外部文件的代码写在最后。比如一些按钮的点击事件,比如轮播图动画的脚本也可以放在最后。

2、defer延迟加载

<script src="" defer></script>
  在文档解析完成开始执行,并且在DOMContentLoaded事件之前执行完成,会按照他们在文档出现的顺序去下载解析。效果和把script放在文档最后</body>之前是一样的。
          注:defer最好用在引用外部文件中使用,用了defer不要使用document.write()方法;使用defer时最好不要请求样式信息,因为样式表可能尚未加载,浏览器会禁止该脚本等待样式表加载完成,相当于样式表阻塞脚本执行。

3、异步加载

  • async异步加载:就是告诉浏览器不必等到加载完外部文件,可以边渲染边下载,什么时候下载完成什么时候执行。
     <script type="text/javascript" src="a.js" async></script>
           注:用了async不要使用document.write()方法;使用async时最好不要请求样式信息,原因和defer一样。
  • script dom element法:这个方法是用js动态创建一个script元素添加在document中。
    <script type="text/javascript">
        (function() {
         var s = document.createElement('script');
         s.type = 'text/javascript';
         s.async = true;                                        //这句可以删除,但是效果不变。
         s.src = 'js/a.js';
         var x = document.getElementsByTagName('script')[0];
         x.parentNode.insertBefore(s, x);
     })();
    </script>

    注意:这种方法会阻止onload事件

  • onload时异步加载:这个和script dom element法差不多但是他不是同时执行js和html,他是等html的文件,图片之类的、页面所有的资源全部加载完成后再下载执行js,这样的方法可以避免阻塞onload事件的触发。
     (function() {
          function async_load(){
              var s = document.createElement('script');
              s.type = 'text/javascript';
              s.async = true;
              s.src = 'js/yibujiaz.js';
              var x = document.getElementsByTagName('script')[0];
              x.parentNode.insertBefore(s, x);
          }
          if (window.attachEvent)
              window.attachEvent('onload', async_load);
          else
              window.addEventListener('load', async_load, false);
      })();
    注:DOMContentLoaded与onload事件不同,DOMContentLoaded是页面解析完成,页面的dom元素可以使用,但是页面的图片、视频等资源可能还没加载完成
原文地址:https://www.cnblogs.com/lmjZone/p/8603241.html