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

    参考:https://www.jianshu.com/p/bf8b5bf5fc90

    javaScript脚本对现代网站来说是必不可少的。当用户访问站点,需要下载各种资源,例如js脚本,CSS,图片,iframe等。

    浏览器下载除js外的资源时,会 并行下载,以提高性能。但下载js脚本时,会禁止并行下载(成为脚本阻塞)。浏览器遇到JS时,必须等JS下载,解析,执行完毕后,才能继续并行下载下一个资源。原因时JS可能会改变页面或者改变JS间的依赖关系,例如A.js中用document.write改变页面,B.js依赖A.js。因此要严格保证顺序,不能并行下载。

         因此不推荐将js放到<head>标签里,浏览器遇到<script>标签会下载,解析,执行完脚本后,才继续处理剩余的页面部分。而且浏览器在遇到<body>标签前是不会渲染页面的。

         所以通常的建议是将JS放到<body>标签底下,可以有最佳的用户体验。但对于大型网站来说,这还不够。虽然js脚本由于存在的依赖关系,需要按顺序执行,但并不需要按顺序下载。

      异步处理脚本:

       通常我们加载JS脚本会在HTML里:

    <script type="text/javascript" src="A.js"></script>

       这属于静态脚本元素,浏览器执行到这里发现script元素,会按上面所说的,下载解析执行脚本,同时阻塞其他资源文件的下载。而动态脚本如下:

    var script = document.createElement('script');  //创建script标签
    script.type = "text/javascript";
    script.src = "A.js";
    document.getElementsByTagName('head')[0].appendChild(script);   //塞进页面

    先用document.createElement('script')生成一个script标签,再设置它的src属性,最后将其插入到<head>中。

    script标签被插入到页面的DOM树后,就会开始下载src属性指定的脚本。而且通过动态脚本元素下载脚本是异步的,不会阻塞页面的其他下载和处理过程,因此script标签插入<head>中也没问题。

    当JS下载完毕后,就会立即执行。如果多个JS间有依赖关系,一下载完马上执行可能会出现error。因此通常来说你应该将有依赖关系的JS合并成一个文件,虽然合并后JS文件会变大,但由于是异步下载,你几乎不会有什么损失。

    如果实在不方便将有依赖关系的文件合并。你需要自己指定先后顺序,通过监听load事件来确保一次加载脚本:

    function loadScript(url, callback){
        var script = document.createElement ("script")
        script.type = "text/javascript";
    
        if (script.readyState){ //IE
            script.onreadystatechange = function(){
                if (script.readyState == "loaded" || script.readyState == "complete"){
                    script.onreadystatechange = null;
                    callback();
                }
            };
        } else { //Others
            script.onload = function(){
                callback();
            };
        }
        script.src = url;
        document.getElementsByTagName("head")[0].appendChild(script);
    }
    
    //严格确保A->B->C,依次下载脚本文件
    loadScript("A-delay.js", function(){
        loadScript("B-delay.js", function(){
            loadScript("C-delay.js", function(){
                console.log("All files are loaded!");
            });
        });
    });

    Script async

    HTML5里为script标签里新增了async属性,用于异步加载脚本:

    <script type="text/javascript" src="alert.js" async="async"></script>

    浏览器解析到HTML里的该行script标签,发现指定为async,会异步下载解析执行脚本。

    Script defer

    script标签里可以设置defer,表示延迟加载脚本:

    <script type="text/javascript" src="alert.js" defer="defer"></script>

    浏览器解析到HTML里的该行script标签,发现指定为defer,会暂缓下载解析执行脚本。而是等到页面加载完毕后,才加载脚本(更精确地说,是载DOM树构建完成后,在window.onload触发前,加载defer的脚本)。

    该方式可以跨域。缺点是虽然不像async属于HTML5的新属性,但defer仍然有旧版本浏览器不支持。

    XHR Eval

    通过传统的Ajax方式,用XMLHttpRequest异步获得脚本内容后,通过eval执行脚本:

    function createRequest() {  
        try {  
            request = new XMLHttpRequest();  
        } catch (tryMS) {  
            try {             
                request = new ActiveXObject("Msxml2.XMLHTTP");    
            } catch (otherMS) {   
                try {  
                    request = new ActiveXObject("Microsoft.XMLHTTP");  
                } catch (failed) {  
                    request = null;  
                }  
            }  
        }
        return request;  
    }  
    
    var request = createRequest();    //获得一个请求对象
    request.onreadystatechange = function() {
        if (request.readyState == 4) {
            if ((request.status >= 200 && request.status < 300) || request.status == 304) {
                eval(request.responseText);
            }
        }
    };
    request.open("GET", "alert.js", true);
    request.send(null);
  • 相关阅读:
    USES_CONVERSION宏(转)
    推送本地仓库至多个远程仓库(转)
    .gitignore的使用
    重命名分支
    不支持尝试执行的操作——————MFC窗口打开错误
    error C1010:在查找预编译头文件时遇到意外的文件结尾——————vs错误
    抓边(一)——————————————使用halcon测量助手
    CString, string, char *之间的相互转换(转)
    css模块化
    继承、原型链、在组件开发上的应用
  • 原文地址:https://www.cnblogs.com/psxiao/p/11552823.html
Copyright © 2011-2022 走看看