JS的异步加载以及对其时间线的理解

异步加载

异步加载又叫非阻塞加载,浏览器在下载执行js的同时,还会继续进行后续页面的处理。主要有三种方式。

  1. 第一种方法 Script DOM Element
(function(){
    var scriptEle = document.createElement("script");
    scriptEle.type = "text/javasctipt";
    scriptEle.async = true;
    scriptEle.src = "http://cdn.bootcss.com/jquery/3.0.0-beta1/jquery.min.js";
    var x = document.getElementsByTagName("head")[0];
    x.insertBefore(scriptEle, x.firstChild);        
 })();

属性是HTML5中新增的异步支持。此方法被称为Script DOM Element方法,Google Analytics 和 Google+ Badge 都使用了这种异步加载代码。

(function(){;
    var ga = document.createElement('script'); 
    ga.type = 'text/javascript'; 
    ga.async = true; 
    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; 
    var s = document.getElementsByTagName('script')[0]; 
    s.parentNode.insertBefore(ga, s); 
})();

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

  1. 第二种方法 onload时的异步加载
(function(){
    if(window.attachEvent){
        window.attachEvent("load", asyncLoad);
    }else{
        window.addEventListener("load", asyncLoad);
    }
    var asyncLoad = function(){
        var ga = document.createElement('script'); 
        ga.type = 'text/javascript'; 
        ga.async = true; 
        ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; 
        var s = document.getElementsByTagName('script')[0]; 
        s.parentNode.insertBefore(ga, s);
    }
)();

这种方法只是把插入script的方法放在一个函数里面,然后放在window的onload方法里面执行,这样就解决了阻塞onload事件触发的问题。

注:DOMContentLoaded与load的区别。前者是在document已经解析完成,页面中的dom元素可用,但是页面中的图片,视频,音频等资源未加载完,作用同jQuery中的ready事件;后者的区别在于页面所有资源全部加载完毕。

  1. 第三种方法
  • defer属性规定是否对脚本执行进行延迟,直到页面加载为止
  • 如果脚本不会改变文档的内容,可将defer属性加入到
<script type="text/javascript" defer></script>

JS时间线

首先,什么是时间线?
它是根据js出生的那一刻开始记录的一系列浏览器按照顺序做的事,形容的就是加载顺序,可以用来优化什么东西。

1、创建document对象,开始解析web页面。创建HTMLHtmlElement对象,添加到document中。这个阶段document.readyState = ‘loading’.(这个时候页面的状态处于loading);

2、遇到link外部css,创建线程加载,并继续解析文档。并发;

3、遇到script外部js,并且没有设置async、defer,浏览器创建线程加载,并阻塞,等待js加载完成并执行该脚本,然后继续解析文档。js拥有修改dom的能力–>domcument.write;

4、遇到script外部js,并且设置有async、defter,浏览器创建线程加载,并继续解析文档;
defer属性设置后,表示加载script外部js和解析html页面是异步,并且等到html解析完成再执行js解析后的代码;
async属性设置后,表示加载script外部js和解析html页面是异步,但是当js解析完成,立刻执行它,此时html解析是被阻塞的;
document.createElement(‘script’)的方式动态插入script元素来模拟async属性,实现脚本异步加载和执行;
document.write():特别特殊他是把里面的东西当成HTML文档输出到页面里去,但是有一点就是,有的时候,当你整个文档全部都解析的差不多的时候再用document.write()的话会把你之前所有的文档流都清空,用它里面的文档流代替。

例:整个页面只显示a,这里的document.write();在这里有消除文档流的功能,连script都消除了。

<div style="height:100px;width:100px;background-color:red;"></div>
<script type="text/javascript">
    window.onload = function(){
        document.write('a');
    }
</script>

5、遇到img等,浏览器创建线程加载(先正常解析dom结构,在异步加载src),并继续解析文档;

6、当文档解析完成,document.readyState = ‘interactive’;
先解析完,再加载完,然后状态位变为interactive(活跃)
查看状态位的转换:

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

7、文档解析完成后,所有设置有defer的脚本会按照顺序执行(注意与async的不同);

8、document对象触发DOMContentLoaded事件,这也标志着程序执行从同步脚本执行阶段,转化为事件驱动阶段;
例1:同时打印出a和complete,而且onDOMContentLoaded是不好使的,只有绑定在addEventListener才好用。

    console.log(document.readyState);
    document.onreadystatechange = function(){
        console.log(document.readyState);
    }
    document.addEventListener('DOMContentLoaded',function(){
        console.log('a');
    },false)

例2:window.onload和下面这个的区别

    $(document).ready(function(){
    //当DOM解析完就执行的部分(不用加载完,加载完是给用户看的,对于我们来说解析完就可以操作了)
    /*它的原理就是interactive和DOMContentLoaded事件*/
    })

区别就是:window.onload满需要都加载完,但是它解析完就可以操作了(这是jQuery的方法)
例3:当把script放在上面时候最好这样写,不要写onload,千万不要写onload,但是最好的方法还是写在下面

<head>
    <meta charset="UTF-8">
    <title>lottery</title>
    <script type="text/javascript">
        document.addEventListener('DOMContentLoaded',function(){
            var div = document.getElementsByTagName('div')[0];
            console.log(div);
        },false)
    </script>
       // script标签写在上面又能处理下面的代码,而且效率还高,因为登高DOM解析完就执行,而不是DOM加载完
</head>

9、当所有async的脚本加载完成并执行后、img等加载完成后,document.readyState = ‘complete’,window对象触发load事件;

10、从此,以异步响应方式处理用户输入、网络事件等。

总结就是三个点:先生成document对象,代表js可以运行了,第二步就是文档解析完了,第三步就是文档加载完了并且执行完了。

发布了23 篇原创文章 · 获赞 0 · 访问量 481

猜你喜欢

转载自blog.csdn.net/weixin_45806273/article/details/104783761
今日推荐