【Hight Performance Javascript】——脚本加载和运行

时间:2023-03-10 00:28:10
【Hight Performance Javascript】——脚本加载和运行

脚本加载和运行

当浏览器遇到一个<script>标签时,无法预知javascript是否在<p>标签中添加内容。因此,浏览器停下来,运行javascript代码,然后继续解析、翻译页面。

浏览器必须首先下载外部文件的代码,这要占用一些时间,然后解析并运行代码,这又要占用一些时间。此过程中,页面解析和用户交互是被完全阻塞的。

将脚本放在底部

【Hight Performance Javascript】——脚本加载和运行

合并脚本减少个数

延迟脚本(defer)

<script src="file1.js" defer></script>

defer属性指明元素中所包含的脚本不打算修改DOM,因此代码可以稍后执行。对应的Javascript文件将在<script>被解析时启动下载,但代码不会立即执行,直到DOM加载完成(在onload事件句柄被调用之前)。拥有defer属性的文件可以用页面的其他资源一起并行下载。

兼容性:只被IE 4+ 和FF 3.5+支持,在其他浏览器,defer属性被忽略。

动态异步加载脚本

动态脚本加载时非阻塞Javascript下载中最常用的模式,因为它可以跨浏览器,而且简单易用。

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

无论在何处启动下载,文件的下载和运行都不会阻塞其他页面处理过程。甚至可以放在<head>部分。

当使用动态脚本节点下载时,返回的代码通常立即执行。当脚本是“自运行”类型时,这一机制运行正常,但如果脚本只包含供页面其他脚本调用的调用接口,则会带来问题。此时,需要跟踪脚本下载完成并准备妥善的情况。使用动态<script>节点发出时间得到相关信息:

function loadScript(url, cb) {
    var script = document.createElement('script');
    script.type = 'text/javascript';
    if(script.readyState) {// IE
        script.onreadyStatechange = function () {
         if(script.readyState === 'load' || script.readyState === 'complete') {
             script.onreadystatechange = null;
             cb();
         }
        }
   }else {// Others
      script.onload = function () {
         cb();
        }
   }
    script.src = 'file1.js';
    document.getElementsByTagName('head')[0].appendChild(script);
}

浏览器不保证文件加载的顺序,下面可以保证脚本按顺序下载并运行:

loadScript('file1.js',function () {
   loadScript('file2.js', function () {
      ...
    })
})

如果多个文件的次序十分重要,更好的方法是讲这些文件按照正确的次序连接成一个文件。

XHR 脚本注入

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

优点:下载不立即执行的javascript代码;同样的代码在所有现代浏览器中都不会引发异常。

缺点:Javascript文件必须与页面放置在同一个域内,不能从CDNs 下载。

推荐的非阻塞模式

推荐的向页面加载大量脚本的方法分为两个步骤:第一步,包含动态加载javascript所需的代码,然后加载页面初始化所需的除javascript之外的部分。这部分尽量小,可能只包含loadScript()函数。当初始代码准备好之后,用它来加载其余的javascript。例如:

<script type="text/javascript" src="loader.js"></script>
<script type="text/javascript">
    loadScript("the-rest.js", function(){
        Application.init();
    });
</script>