zoukankan      html  css  js  c++  java
  • Javascript 文件的同步加载与异步加载

    HTML 4.01 的script属性

    charset: 可选。指定src引入代码的字符集,大多数浏览器忽略该值。
    defer: boolean, 可选。延迟脚本执行,相当于将script标签放入页面body标签的底部,js脚本会在document的DOMContentLoaded之前执行。除IE和较新版本的Firefox外,其他浏览器并未支持。
    language: 已废弃。大部分浏览器会忽略该值。
    src: 可选。指定引入的外部代码文件,不限制后缀名。
    type: 必选。指定脚本的内容类型(MIME类型)。现实中通常不指定该值也可以,浏览器会默认当作text/javascript类型来解释执行。

     

    HTML5中的script属性:

    script 标签在HTML5中除了具备HTML5新标准定义的属性以外,和HTML4.01相比移除了language属性,修改了type属性为可选的(默认text/javascript),并新增了一个属性async。

    async :boolean, 属性的作用,定义脚本是否异步执行,取值true或false。

    如果 async 设为 true ,会忽略 defer 属性。

    异步执行的 js 文件被假定为不使用 document.write()  向加载中的 document 写入内容,因此不要在 异步执行的 js 文件的加载执行过程中使用 document.write()

    除了 script 标签属性外,页面引入 js 文件的方式影响其加载执行方式:

    • 任何以添加 script 节点(例如 appendChild(scriptNode) ) 的方式引入的js文件都是异步执行的 (scriptNode 需要插入document中,只创建节点和设置 src 是不会加载 js 文件的(IE6-9 除外),这跟 img 的预加载不能类比 )  ,无需特别设置script.type,如果过设置,需要设置为 javascript 类型,否则不会加载 js 文件(text/javascript ,或者带版本号的,如果有特殊需求)
    • html文件中的<script>标签中的代码或src引用的js文件中的代码是同步加载和执行的(较新的浏览器对阻塞的 js 可以并行加载了,但执行依然是同步的)
    • html文件中的<script>标签中的代码使用document.write()方式引入的js文件是异步执行的
    • html文件中的<script>标签src属性所引用的js文件的代码内再使用document.write()方式引入的js文件是同步执行的
    • 使用 Image 对象异步预加载 js 文件(不会被执行,onload 事件不会触发,但是会触发onerror)

    不要使用类似下面这种做法,这样并不会发起加载 js 文件的请求:

    divNode.innerHTML = '<script src="xxx.js"></script>';

    window.onload 事件会在 js 文件加载完毕才触发(即使是异步加载,还有 iframe 中网页的加载  )

    =====================================================

    1、

    <script>

    //同步加载执行的代码

    </script>

    2、

    <script src="xx.js"></script>  //同步加载执行xx.js中的代码

    因为是同步的,可以使用document.wirte(), 比如 jsonp ,嵌入一个 js 文件,从服务器取数据并用服务器脚本输出 js 代码向 document 中写入内容.

    3、

    <script>

    document.write('<script src="xx.js"><\/script>');   //异步加载执行xx.js中的代码

    </script>

    4、

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

    xx.js中有下面代码:

    document.write('<script src="11.js"><\/script>');   

    document.write('<script src="22.js"><\/script>');   

    则xx.js和11.js、22.js 都是同步加载和执行的。

    如果 xx.js 、11.js 和 22.js 以插入 script 节点方式异步加载,则 11.js 和 22.js 是异步加载的,

    如果 xx.js 以script 节点方式异步加载,  11.js 和 22.js 以 document.write(script) 方式加载,则 11.js 和 22.js 是同步加载的(经最新的浏览器测试, 在chrome 下,xx.j 异步加载执行已经无法使用 document.write() 向文档写入内容,不过如果不在document 加载过程插入,在插入之前使用 document.write() 开启对页面的重写,则异步加载的 js 仍能写入内容,比如页面上一个 按钮的 onclick 回调函数里面document.write(1),然后 headNode.appendChild(scriptNode) ,但是 firefox 和IE 却可以在 document 关闭之前写入(方法是在 xx.js中alert阻止文档关闭))

    测试:在11.js中 alert()(最好的方式是使用 服务器脚本输出js代码,在输出前延迟 iao几秒 , 比如  php : sleep(5) ;不要用 for 循环,js 引擎是单线程执行的,持续执行任何一段代码都会导致其余代码被阻塞)   , 22.js 中  console.log()  ,可以看到 22.js中的代码被阻塞.

    5、

    下面这种方式,xx.js会在appendChild执行之后异步加载执行

    var script = document.createElement("script");

    script.setAttribute("src","xx.js");

    documenrt.getElementsByTagName("head")[0].appendChild(script);

    6、使用 Image 对象异步预加载 js 文件(不会被执行)

    Image 的 src 被赋值时即发起请求,而且对文件类型不挑剔(图片也可能是有脚本动态创建的,比如验证码),因此可以将 js 文件的 url 赋给 image.src, js 加载之后被浏览器缓存.

    复制代码
    var img = new Image(); 
    img.onload = function(){ alert(1); } ; //由于返回的js文件 MIME  不是图片,onload回调函数并不会被触发
    img.src = 'http://localhost/test/loadjs/try.2.js';
    var s = document.createElement("script");
    var h = document.getElementsByTagName("head")[0];
    
    //执行 js
    s.src=img.src;
    h.appendChild(s);
    复制代码

     在检测 文件 加载完毕时有一点问题,可以使用非标准的 image.complete ,该属性在 chrome 和 firefox 下只有文件加载过程中才是 false(即使onerror中也是true),而在IE9下在onload 后为 true,未开始加载、加载过程中、加载失败 都是 false,在 IE8 及IE8 以下, onload 中仍然是 false ,需要设置延时检测才能检测到 true,另外,IE 的图片对象在加载之后无论是否成功,会获得一个占位符的图片尺寸,可以通过这个尺寸来检测是否已经完成加载过程的执行(无论 onerror 还是 onload)。

    复制代码
    var im = new Image();
    console.log([1,im.complete,im.width,im.readyState]);
    im.onerror=im.onload = function(event){ 
        var e = event||window.event;
            var eventType = e.type;
            var host = this;
        console.log(['callback ',eventType ,host.complete,host.width,host.readyState]);
        setTimeout(function(){// for ie8-
            console.log(['callback delay ',eventType ,host.complete,host.width,host.readyState]);
        },100); 
    }
    im.src="http://seajs.org/dist/sea.js";
    console.log([1,im.complete,im.width,im.readyState]);
    复制代码

    在 IE 中 image 对象有 onreadystatechange 事件, 该事件仅在 成功加载图片后执行,加载 js 文件不会触发该事件

    复制代码
    var im = new Image();
    console.log([im.complete, im.readyState]); // false,uninitialized 
    im.onreadystatechange = function(){ 
      console.log([im.complete, im.readyState]); //false,complete 
       setTimeout(function(){ 
              console.log([im.complete, im.readyState]); //true,complete 
    
        },100);
     }
    im.src = "http://www.baidu.com/img/baidu_sylogo1.gif";
    复制代码

      

     一个加载 js 文件的 函数:

    复制代码
    var loadJS = function(url,callback){  
    var head = document.getElementsByTagName('head');  
    if(head&&head.length){
    head = head[0];
    }else{
    head = document.body;
    }
    
    var script = document.createElement('script');   
    
    script.type = "text/javascript";   
    head.appendChild( script);
    
    script.onload = script.onreadystatechange = function(){
    //script 标签,IE 下有 onreadystatechange 事件, w3c 标准有 onload 事件     
    //这些 readyState 是针对IE8及以下的,W3C 标准的 script 标签没有 onreadystatechange 和 this.readyState , 
    //文件加载不成功 onload 不会执行,
    //(!this.readyState) 是针对 W3C标准的, IE 9 也支持 W3C标准的 onload if ((!this.readyState) || this.readyState == "complete" || this.readyState == "loaded" ){ callback(); } }//end onreadystatechange }
     script.src = url;   
    复制代码

    对于第4点的测试(同步加载)(其中插入 alert 很容易看到加载时的阻塞)

    tryjs.html

    复制代码
    <!DOCTYPE html>
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    
    <script src="tryjs.js" 
    onload="if(!document.all){console.log('outer js callback, not IE');}" 
    onreadystatechange="console.log('outer js callback ',this.readyState,' IE');"></script>
    
    
    <body>
    
    </body>
    </html>
    复制代码

    tryjs.js

    复制代码
    console.log('write begin');
    document.write('<script src="try.1.js" onreadystatechange="console.log(\'file 1 callback \',this.readyState,\' IE\');" onload="if(!document.all){console.log(\'file 1 callback,NOT IE \');}"><\/script>');
    document.write('<script src="try.2.js" onreadystatechange="console.log(\'file 2 callback \',this.readyState,\' IE\');" onload="if(!document.all){console.log(\'file 2 callback,NOT IE \');}"><\/script>');
    console.log('write finished');
    复制代码

    try.1.js

    console.log('loadjs 1 begin');
    console.log('loadjs 1 finished');

    try.2.js

    console.log('loadjs 2 begin');
    console.log('loadjs 2 finished');

    测试结果(file 2 和 file 1 的 callback complete 在IE7\8\9次序不确定

    IE 7:
    日志: outer js callback loading IE 
    日志: outer js callback loaded IE 
    日志: write begin 
    日志: write finished 
    日志: outer js callback complete IE 
    日志: file 1 callback loading IE 
    日志: file 2 callback loading IE 
    日志: loadjs 1 begin 
    日志: loadjs 1 finished 
    日志: loadjs 2 begin 
    日志: loadjs 2 finished 
    日志: file 2 callback complete IE 
    日志: file 1 callback complete IE 


    IE8:
    日志: outer js callback loading IE 
    日志: outer js callback loaded IE 
    日志: write begin 
    日志: write finished 
    日志: outer js callback complete IE 
    日志: file 1 callback loading IE 
    日志: file 2 callback loading IE 
    日志: loadjs 1 begin 
    日志: loadjs 1 finished 
    日志: loadjs 2 begin 
    日志: loadjs 2 finished 
    日志: file 2 callback complete IE 
    日志: file 1 callback complete IE 

    IE9:
    日志: write begin 
    日志: write finished 
    日志: outer js callback complete IE 
    日志: file 1 callback loading IE 
    日志: file 2 callback loading IE 
    日志: loadjs 1 begin 
    日志: loadjs 1 finished 
    日志: loadjs 2 begin 
    日志: loadjs 2 finished 
    日志: file 1 callback complete IE 
    日志: file 2 callback complete IE 



    FIREFOX:
    write begin 
    write finished
    outer js callback, not IE
    loadjs 1 begin
    loadjs 1 finished
    file 1 callback,NOT IE
    loadjs 2 begin
    loadjs 2 finished
    file 2 callback,NOT IE


    CHROME:
    write begin     
    write finished    
    outer js callback, not IE    
    loadjs 1 begin    
    loadjs 1 finished    
    file 1 callback,NOT IE 
    loadjs 2 begin    
    loadjs 2 finished    
    file 2 callback,NOT IE

    //=========几个测试文件(这是最近另外测的)============

    files in  /test/loadjs/

    https://files.cnblogs.com/ecalf/loadjs.rar

    原文链接:http://www.cnblogs.com/ecalf/archive/2012/12/12/2813962.html

  • 相关阅读:
    POJ 1659 Frogs' Neighborhood
    zoj 2913 Bus Pass(BFS)
    ZOJ 1008 Gnome Tetravex(DFS)
    POJ 1562 Oil Deposits (DFS)
    zoj 2165 Red and Black (DFs)poj 1979
    hdu 3954 Level up
    sgu 249 Matrix
    hdu 4417 Super Mario
    SPOJ (BNUOJ) LCM Sum
    hdu 2665 Kth number 划分树
  • 原文地址:https://www.cnblogs.com/yimu/p/3067159.html
Copyright © 2011-2022 走看看