高性能JavaScript chapter 1 : 加载和执行

2017-04-03  本文已影响0人  张朝阳_cecurs

如何用最高效的方式把javascript代码加载到页面中呢?
1、脚本位置
每个文件必须等到前一个文件下载并执行完成才会开始下载。在这些文件逐个下载过程中,用户看到的是一片空白。称为脚本阻塞。因此推荐将所有的标签尽可能放到标签的底部,以尽量减少对整个页面下载的影响。

<html>
<head>
    <title>script example</title>
    <link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
    <p>Hello world!</p>
    <!-- 推荐的脚本存放位置 -->
    <script type="text/javascript" src="file1.js"></script>
    <script type="text/javascript" src="file2.js"></script>
    <script type="text/javascript" src="file1.js"></script>
</body>
</html>

2、组织脚本
(1)浏览器在解析HTML页面的过程中,每遇到一个<script>标签,都会因执行脚本而导致一定的延时,所以减少页面所包含的<script>标签数量有助于改善页面性能。
(2)HTTP请求会带来额外的性能开销,因此下载单个100KB的文件将比下载4个25KB的文件更快。即,减少页面中外链脚本文件的数量将会改善性能。
综述:用文件打包工具把多个文件合并成1个,这样只需要引用一个<script>标签,就可以减少性能消耗。

<html>
<head>
    <title>script example</title>
    <link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
    <p>Hello world!</p>
    <!-- 推荐的脚本存放位置 -->
    <script type="text/javascript" src="file1.js"></script>
</body>
</html>

3、无阻塞的脚本
秘诀:在页面加载完成后才加载JavaScript代码。
(1)延迟的脚本
带有defer属性的JavaScript文件将在页面解析到<script>标签时开始下载,但并不会执行,下载时,不会阻塞浏览器的其他进程,可以与页面中其他资源并行下载。它下载完成后,在onload事件被触发前执行。
该属性只有IE4+ 和 firefox3.5+ 的浏览器支持。

<head>
    <title>script defer example</title>
    <link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
    <script defer>
        alert("defer");
    </script>
    <script>
        alert("script");
    </script>
    <script>
        window.onload = function(){
            alert("load");
        }
    </script>
</body>
</html>

<small>该 示例 在支持defer属性的浏览器上,弹出的顺序是:script , defer , load.</small>
(2)动态脚本文件
该脚本文件被添加到页面时开始下载,无论在何时启动下载,文件的下载和执行过程不会阻塞页面其他进程。

<html>
<head>
    <title>动态 script example</title>
</head>
<body>
    <script>
        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 { // 其他浏览器
                script.onload = function(){
                    callback();
                }
            }
            script.src = url ;
            document.getElementByTagName("head")[0].appendChild(script);
        }
        loadScript("file1.js" , function(){
            alert("file is loaded !");
        })
    </script>
</body>
</html>

<small>该 示例 用到<script>的readyState属性,该属性有5种取值:
uninitialized 初始状态
loading 开始下载
loaded 下载完成
interactive 数据完成下载但尚不可使用
complete 所有数据已准备就绪</small>
(3)XMLHttpRequest(xhr对象) 脚本注入
优点1:你可以把脚本的执行推迟到你准备好的时候。
优点2:在所有主流浏览器都能正常使用。
缺点:JavaScript文件必须与所请求的页面属于相同的域。

<html>
<head>
    <title>xhr script example</title>
</head>
<body>
    <script>
        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);
    </script>
</body>
</html>

<small>这段代码发送一个get请求获取file1.js文件。事件处理函数onReadyStateChange 检查readyState 是否为4 ,同时校验HTTP状态码是否有效(2XX 表示有效响应,304意味着是从缓存读取)。如果收到了有效响应,就会创建一个<script>元素,设置该元素的text属性为从服务器接收到的responseText。</small>
(4)作者推荐的无阻碍模式

<html>
<head>
    <title>YUI3 example</title>
</head>
<body>
    <script src="http://yui.yahooapis.com/3.18.1/build/yui/yui-min.js"></script>
    <script>
    // Create a YUI sandbox on your page.
    YUI().use('node', 'event', function (Y) {
        // The Node and Event modules are loaded and ready to use.
        // Your code goes here!
    });
    </script>
</body>
</html>
<html>
<head>
    <title>LazyLoad example</title>
</head>
<body>
    <script type="text/javascript" src="lazyload.js"></script>
    <script>
        LazyLoad.js("the-rest.js",function(){
            
            Application.init();
        });
    </script>
</body>
</html>
<html>
<head>
    <title>LABjs example</title>
</head>
<body>
    <script type="text/javascript" src="LAB.js"></script>
    <script>
        $LAB.script("first-file.js").wait()
            .script("the-rest.js")
            .wait(function(){
                Application.init();
            });
    </script>
</body>
</html>

<small>在前面的例子中,不能保证first-file.js的代码在the-rest.js的代码前执行。
为了确保这一点,你必须在第一个script()方法后调用wait(),比如,
如下示例可以保证first-file.js的代码在the-rest.js的代码前执行。</small>

<html>
<head>
    <title>LABjs example</title>
</head>
<body>
    <script type="text/javascript" src="LAB.js"></script>
    <script>
        $LAB.script("first-file.js").wait()
            .script("the-rest.js")
            .wait(function(){
                Application.init();
            });
    </script>
</body>
</html>
上一篇下一篇

猜你喜欢

热点阅读