2

当浏览器遇到<script>标签时,页面的加载、介些都会停下来,运行此javascript代码,然后再继续加载。这种事情同样会发生在那些以"src"属性调用的外部脚本,浏览器首先下载外部文件的代码,这要占用一些时间,然后在运行这些代码,这又要占用一些时间。此过程中,页面的解析与用户的交互都是阻塞的。

脚本的位置

不管是内联脚本还是外部脚本,都应该尽量放在<body>标签结束之前(除非某些脚本需要在页面加载完之前调用),这样可以保证在运行脚本之前,页面已经基本加载完成。

非阻塞脚本

  • 延时脚本
    可以给script标签添加一个属性 - defer ,这个属性表明:元素中的脚本不打算修改DOM,因此代码可以稍后执行。带有这个属性的任何script元素中的脚本都不会在DOM加载完之前执行,如果是外部脚本,这些脚本首先并行下载,而不会执行,所以不会阻塞页面的加载。实例代码如下:
    <script src="./script/file1.js" defer>

  • 动态脚本元素
    DOM允许你通过脚本来创建script元素,像下面这样:

var script = document.createElement("script");
script.type = "text/javascript";
script.src = "./script/file1.js";
document.getElementsByTagName("head")[0].appendChild(script);

此文件元素添加到页面后立即开始下载。此技术的重点在于:无论在何处启动下载,脚本的下载和运行都不会阻塞页面的处理过程。
为方便使用,我整合了一个动态加载脚本的方法:

function loadJS(url, callback) {
var script = document.creatElement("script");
    script.type = "text/script";
if(script.readyState) {
        script.onreadystatechange = function() {
            if(script.readyState == "loaded" || script.readyState == "complete") {
                script.onreadystatechange = null;
                callback;
            }
        };
    }else {
        script.onload = function() {
            callback();
        };
    }
script.src = url;
    document.getElementsByTagName("head")[0].appendChild(script);
}
  • XMLHttpRequest 脚本注入
    另一个以非阻塞的方式获得脚本的方法是使用XHR对象将脚本注入到页面中。此技术先创建一个XHR对象,然后下载脚本文件,接着用一个动态的script元素将javascript代码注入页面:

var xhr = new XMLHttpRequest();
xhr.open("get", "./scripts/file1.js", true);
xhr.onreadystatechange = function(){
            if(xhr.readyState == 4) {
                if(xhr.status >= 200 && xhr.status < 300 || xhr.status == 400) {
                    var script = document.createElement("script");
                    script.type = "text/javascript";
                    script.text = xhr.responseText;
                    document.body.appendChild(script);
                }
            }
        };
xhr.send(null);
};

此方法的限制是,你必须下载同一个域下的文件,不能从CDN下载。


MockingBird
5.8k 声望743 粉丝