JavaScript异步加载和网页渲染过程

JavaScript异步加载原理分析

  1. 什么是网页渲染的过程?
  2. 什么是同步加载?
  3. 什么是异步加载?

网页的渲染过程

页面的渲染过程:DOMTree + CSSTree = renderTree

  1. 构建文档对象模型(DOM)
  2. 构建CSS对象模型(CSSOM)
  3. 构建渲染树(Render Tree)
  4. 布局(Layout)
  5. 绘制(Painting)

网页渲染过程

什么是同步(Synchronous)加载?

我们平时使用的最多的一种方式:<script src="http://zhangsan.com/script.js"></script>

同步模式,又称阻塞模式,会阻止浏览器的后续处理,停止后续的解析,只有当当前加载完成,才能进行下一步操作

优点:安全性高

缺点:会照成网页的堵塞

建议:把<script>标签放在<body>结尾处,这样尽可能减少页面阻塞。

什么是异步(Asynchronous)加载?

异步加载又叫非阻塞加载,浏览器在下载执行js的同时,还会继续进行后续页面的处理

  • 代码执行时间:当整个网页解析完,执行代码(在网页而加载完之前)

主要有三种方式:

  1. Script DOM Element(<async>属性是HTML5中新增的异步支持)浏览器部分不支持
    <script async></script>

    (function(){
        var scriptEle = document.createElement('script');
        scriptEle.type = "text/javascript"
        scriptEle.async = true;
        scriptEle.src = "xxx.js";
    
        var head = document.getElementsByTagName("head")[0];
        head.insertBefore(scriptEle, head.firstChild); 
    })();
    
    • 加载完就执行,只能加载外部脚本 W3C的标准
    • 该加载方式执行完之前会阻止onload事件的触发,而现在很多页面的代码都在onload时还执行额外的渲染工作,所以还是会阻塞部分页面的初始化处理
    • 如果有多个声明了async的脚本,其下载和执行也是异步的,不能确保彼此的先后顺序
    • async会在load事件之前执行,但并不能确保与DOMContentLoaded的执行先后顺序
  2. IE专用(IE9以下) (defer)
    <script defer></script>

    (function(){
        var scriptEle = document.createElement('script');
        scriptEle.type = "text/javascript"
        scriptEle.defer = true;
        scriptEle.src = "xxx.js";
    
        var head = document.getElementsByTagName("head")[0];
        head.insertBefore(scriptEle, head.firstChild); 
    })();
    
    • defer适用于外联脚本,如果script标签没有指定src属性,只是内联脚本,尽量不要使用defer (虽然IE4-IE7还支持对嵌入脚本的defer属性,但在IE8及之后的版本就只支持外部脚本,对不支持的会直接忽略defer属性)
    • 如果有多个声明了defer的脚本,则会按顺序下载和执行
    • defer脚本会在DOMContentLoaded和load事件之前执行
    • 使浏览器延迟脚本的执行,直到浏览器解析和渲染完页面
  3. 自己写一个把<script>标签插入到网页的最后面

    // 异步载入并执行脚本
    function loadasync(url){
        // 找到head标签
        var head = document.getElementsByTagName('head')[0];
        // 创建一个script元素
        var s = document.createElement('script');
        // 设置引入地址
        s.src = url;
        // 插入到head标签中
        head.appendChild(s);
    }
    
    • 注意这个loadasync()函数会动态的载入脚本–脚本载入到文档中,成为正在执行的JavaScript程序的一部分,既不是通过web页面内联包含,也不是来自web页面的静态引用

解决异步加载的方法:

  1. 利用定时器的延时

    // 异步的过程
    var script = document.createElement("script");
    script.src = "test.js";
    document.head.appendChild(script);
    
    setTimeout("test()", 1000);
    
    • 弊端就是不知道准确时间
  2. 加载事件onload

    window.onload =  function(){
        test();
    }
    
    • 低版本的IE可能不支持,并且效率太慢
  3. 咱自己写一个

    // url: 地址
    // callback: 回调函数
    function loadScript(url, callback){
        var scriptEle = document.createElement('script');
        scriptEle.type = "text/javascript";
    
        if(scriptEle.readyState){
            // 状态码 readyState-->complete loaded 表示ie中script加载完成了
            scriptEle.onreadystatechange = function (){
                if(scriptEle.readyState == 'complete' || scriptEle.readyState == 'loaded'){
                  callback();
                }
            }
        }else{
            //加载完成的标志
            scriptEle.onload = function(){
                // safari  chrome firefox opren
                callback();
            }
        }
        //下载了指定地址的js文件
        scriptEle.src = url;
        //挂到DOM树上,此时才执行了js文件中的代码
        document.head.appendChild(scriptEle);
    }
    
发布了43 篇原创文章 · 获赞 3 · 访问量 1128

猜你喜欢

转载自blog.csdn.net/qq_45007419/article/details/104808096