zoukankan      html  css  js  c++  java
  • js 异步加载

    一、为什么要JS异步加载?

    因为同步加载存在问题!

    JS在默认情况下是以同步模式(又称阻塞模式)加载的,这里“加载”的意思是“解释、执行”。在最新版本的浏览器中,浏览器对于代码请求的资源都是瀑布式的加载,而不是阻塞式的,但是JS的执行总是阻塞的。这会引起什么问题呢?如果在页面中加载一些JS,但其中某个请求迟迟得不到响应,位于此JS后面的JS将无法执行,同时页面渲染也不能继续,用户看到的就是白屏(此时JS在<head>标签之后引入)

    <head>
           <meta charset="UTF-8">
           <title>test</title>
           <script type="text/javascript" src='http://china-addthis.googlecode.com/svn/trunk/addthis.js'></script>
           <script type="text/javascript" src='http://libs.baidu.com/jquery/2.0.0/jquery.min.js'></script>
    </head>
    <body>
       <p>我是小仙女</p>
    </body>
    

    这是一个简单的html文件,页面的主体是简单地文本段落,但是代码执行后迟迟都是空白。为什么呢?因为第一个请求的JS迟迟无法加载,于是阻塞了后面代码的执行,页面得不到渲染。
    那该怎么办呢?你可能会想到一个方法,把JS代码放到</body>标签之前!好主意!于是我们把JS放在HTML语句后面(这也是所提倡的页面结构)。

    <head>
        <meta charset="UTF-8">
        <title>test</title>
    </head>
    <body>
       <p>我是小仙女</p>
       <script type="text/javascript" src='http://china-addthis.googlecode.com/svn/trunk/addthis.js'></script>
       <script type="text/javascript" src='http://libs.baidu.com/jquery/2.0.0/jquery.min.js'></script>
    </body>
    

    页面瞬间被渲染,问题似乎解决了,可是...

    <head>
        <meta charset="UTF-8">
        <title>test</title>
    </head>
    <body>
       <p>我是小仙女</p>
       <script type="text/javascript" src='http://china-addthis.googlecode.com/svn/trunk/addthis.js'></script>
       <script type="text/javascript" src='http://libs.baidu.com/jquery/2.0.0/jquery.min.js'></script>
       <script type="text/javascript">
          alert("hello world");
       </script>
    </body>
    

    我们在前面代码的基础上简单加了一段代码,但"hello world"迟迟无法被弹出,显然是因为前面的JS请求阻塞了后面代码的加载。这时同步加载的问题依然存在:改变JS的加载位置只能改变页面的渲染,JS还是会阻塞。

    二、如何实现JS异步加载?

    异步加载即非阻塞加载,浏览器在加载JS的同时,还会继续进行后续页面的处理。在本例中,我们想实现在请求第一段谷歌提供的JS的同时,下面的JS不受影响,继续执行。
    如何实现?现在提供常用的几种方法:

    1.动态生成<script>标签
    <head>
        <meta charset="UTF-8">
        <title>test</title>
    </head>
    <body>
       <p>我是小仙女</p>
       <script type="text/javascript">
       (function(){
          var s=document.createElement("script");
          s.type="text/javascript";
          s.src="http://china-addthis.googlecode.com/svn/trunk/addthis.js";
          document.body.appendChild(s);
       })();
       </script>
       <script type="text/javascript" src='http://libs.baidu.com/jquery/2.0.0/jquery.min.js'></script>
       <script type="text/javascript">
          alert("hello world");
       </script>
    </body>
    

    但是上面的代码还有点问题,这种加载方式在加载执行完之前会阻止onload事件的触发,而现在很多页面的代码都在onload时执行额外的渲染工作等,所以还是会阻塞部分页面的初始化处理。

    <head>
        <meta charset="UTF-8">
        <title>test</title>
    </head>
    <body>
       <p>我是小仙女</p>
       <script type="text/javascript">
       (function(){
          //function lazy(){
            var s=document.createElement("script");
            s.type="text/javascript";
            s.src="http://china-addthis.googlecode.com/svn/trunk/addthis.js";
            document.body.appendChild(s); 
         // }
         // window.addEventListener("load",lazy,false);
       })();
       window.onload=function(){
          alert("hello world");
       };
       </script>
       <script type="text/javascript" src='http://libs.baidu.com/jquery/2.0.0/jquery.min.js'></script>
    </body>
    

    上面带注释的代码不能很好的渲染"hello world",因为存在阻塞onload事件问题;可以把注释去掉,让谷歌提供的JS在onload时才开始异步加载,这就解决了上述问题。

    2.async属性

    async是HTML5的新属性,该属性规定一旦脚本可用,则会异步执行(一旦下载完毕就会立刻执行)。
    需要注意的是:async属性仅适用于外部脚本(只有在使用src属性时)。

    <head>
        <meta charset="UTF-8">
        <title>test</title>
    </head>
    <body>
       <p>我是小仙女</p>
       <script type="text/javascript" src='http://china-addthis.googlecode.com/svn/trunk/addthis.js' async="async"></script>
       <script type="text/javascript" src='http://libs.baidu.com/jquery/2.0.0/jquery.min.js'></script>
       <script type="text/javascript">
          alert("hello world");
       </script>
    </body>
    
    3.defer属性

    defer属性规定是否对脚本执行进行延迟,直到页面加载为止。
    之前只有IE的hack支持defer属性,现在H5开始全面支持defer属性。

    <head>
        <meta charset="UTF-8">
        <title>test</title>
    </head>
    <body>
       <p>我是小仙女</p>
       <script type="text/javascript" src='http://china-addthis.googlecode.com/svn/trunk/addthis.js' defer="defer"></script>
       <script type="text/javascript" src='http://libs.baidu.com/jquery/2.0.0/jquery.min.js'></script>
       <script type="text/javascript">
          alert("hello world");
       </script>
    </body>
    

    asyncdefer看起来差不多呀?而且经常一起出现!来辨析一下

    a.如果没有asyncdefer属性,那么浏览器会立即执行当前的JS脚本,阻塞后面的脚本;
    b.如果有async属性,加载和渲染后续文档的过程和当前JS的加载与执行并行进行(异步),它是乱序执行的,不管你声明的顺序如何,只要它加载完了就会执行;
    c.如果有defer属性,加载后续文档元素的过程和JS的加载是并行进行(异步)的,但是JS的执行在所有元素解析完成之后进行,而且它是按照加载顺序执行脚本的
    4.其他方式

    a.XHR注入(通过XMLHttpRequest对象来获取JS,然后创建一个script元素插入到DOM结构中);
    b.ajax eval(使用ajax得到脚本内容,然后通过eval(xmlhttp.responseText)来运行脚本);
    c.iframe等



    作者:寻找薛定谔的猫
    链接:https://www.jianshu.com/p/3aa3a3e27417
    來源:简书
    简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
  • 相关阅读:
    PHP保留小数的相关方法
    ASP.NET Core MVC 之过滤器(Filter)
    ASP.NET Core MVC 之控制器(Controller)
    ASP.NET Core MVC 之视图组件(View Component)
    ASP.NET Core MVC 之局部视图(Partial Views)
    标签助手(TagHelper)
    ASP.NET Core MVC 之布局(Layout)
    ASP.NET Core MVC 之视图(Views)
    ASP.NET Core MVC 之模型(Model)
    九卷读书:淘宝从小到大的发展 -重读《淘宝技术这十年》
  • 原文地址:https://www.cnblogs.com/niudaxianren/p/9988071.html
Copyright © 2011-2022 走看看