zoukankan      html  css  js  c++  java
  • 高性能javascript(第一章 加载和运行)

     高性能javascript(第一章 加载和运行)

    1、当 JavaScript 运行时其他的事情不能被浏览器处理 

      页面生命周期 

    <script>标签的出现使整个页面的下载和解析因脚本解析、运行而出现等待 ,即无论javascript代码是如何引入的

    <html>
    <head>
        <title>Script Example</title>
    </head>
    <body>
    <p>
        <script type="text/javascript">
            document.write("The date is " + (new Date()).toDateString());
        </script>
    </p>

     <div>
       <script src="1.js"></script>
     </div>

    </body>

    </html>

      分析:浏览器解析页面  =>  遇到p  =>  浏览器停下来,运行js代码  =>  浏览器继续解析div  => 遇到js 、 src属性下载js  、运行js代码

      在下载解析和运行js代码的过程中、页面解析和用户交互是被完全阻塞的。 

    <html>
    <head>
        <title>Script Example</title>
        <-- Example of inefficient script positioning -->
        <script type="text/javascript" src="file1.js"></script>
        <script type="text/javascript" src="file2.js"></script>
        <script type="text/javascript" src="file3.js"></script>
        <link rel="stylesheet" type="text/css" href="styles.css">
    </head>
    <body>
    <p>Hello world!</p></body>
    </html>

      浏览器在遇到<body>标签之前,不会渲染页面的任何部分 ,

    图解:原先的浏览器不支持并行下载js文件

    虽然ie8以上的较先的浏览器支持并行下载,即一个<script>标签不必阻塞<script>标签,但是JavaScript 的下载仍然要阻 塞其他资源的下载过程,例如图片。 并且同样需要所有的js代码下载执行完毕以后才会继续解析页面


    改进一:将脚本放在底部。这样就可以在下载执行解析js代码之前就可以让页面显示传在用户面前

    <html>
    <head>
        <title>Script Example</title>
        <link rel="stylesheet" type="text/css" href="styles.css">
    </head>
    <body>
    <p>Hello world!</p>
    <-- Example of recommended script positioning -->
    <script type="text/javascript" src="file1.js"></script>
    <script type="text/javascript" src="file2.js"></script>
    <script type="text/javascript" src="file3.js"></script>
    </body>
    </html>

    HTTP请求:下载一个100k的文件比下载四个25k的文件要快,YUI库的联合句柄

    <html>
    <head>
        <title>Script Example</title>
        <link rel="stylesheet" type="text/css" href="styles.css">
    </head>
    <body>
    <p>Hello world!</p>
    <-- Example of recommended script positioning -->
    <script type="text/javascript" src="http://yui.yahooapis.com/combo?2.7.0/build/yahoo/yahoo-min.js&2.7.0/build/event/event-min.js"></script>
    </body>
    </html>

     非阻塞方式一:

    尽管下载一个大 JavaScript 文件只产生一次 HTTP 请求,却会锁定浏览器一大段时间。

    非阻塞脚本的秘密在于,等页面完成加载之后,再加载 JavaScript 源码。从技术角度讲,这意味着在 window 的 load 事件发出之后开始下载代码。有几种方法可以实现这种效果。

    指定defer属性的<script>立即启动下载,但是代码不会立即执行,直到dom 加载完毕

    <html>
    <head>
        <title>Script Defer Example</title>
    </head>
    <body>
    <script defer>
        alert("defer");
    </script>
    <script>
        alert("script");
    </script>
    <script>
        window.onload = function () {
            alert("load");
        }; 
    </script>
    </body>
    </html>

    支持defer的浏览器输出的顺序: “script”,“defer”和“load”。 

    不支持defer的浏览器的输出顺序:“defer”,“script”和“load” 


    动态脚本元素 (即使用dom的方法创建script)

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

    技术的重点在于: 无论在何处启动下载,文件的下载和运行都不会阻塞其他页面处理过程 。

    ff/opera/chrome的load事件:

        var script = document.createElement("script");
        script.type = "text/javascript";
        //Firefox, Opera, Chrome, Safari 3+ 
        script.onload = function () {
            alert("Script loaded!");
        };
        script.src = "file1.js";
        document.getElementsByTagName_r("head")[0].appendChild(script);

    ie中readystatechange事件状态:(5种取值) :

    兼容版本:

        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_r("head")[0].appendChild(script);
        }

    但要注意,浏览器不保证文件加载的顺序 ,但是你可以使用下面的方式保证按序加载:

        loadScript("file1.js", function () {
            loadScript("file2.js", function () {
                loadScript("file3.js", function () {
                    alert("All files are loaded!");
                });
            });
        });

    如果多个文件的次序十分重要,最好的办法还是将这些文件按照正确的次序合并成一个文件


     非阻塞方式二: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);

    两个优点:

    1、你可以下载不立即执行的 JavaScript 代码。由于代码返回在<script>标签之外(换句话说不受<script>标签约束),它下载后不会自动执行,这使得你可以推迟执行,直到一切都准备好了。

    2、同样的代码在所有现代浏览器中都不会引发异常。 

    此方法最主要的限制是:JavaScript 文件必须与页面放置在同一个域内。


     

    1、推荐的非阻塞模式 :

    第一种方式:包含动态加载 JavaScript 所需的代码(如loadScript), 然后加载页面初始化所需的除 JavaScript 之外的部分。例如: 

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

    将此代码放置在 body 的关闭标签</body>之前。这样做有几点好处:

    首先,确保 JavaScript 运行不会影响页面其他部分显示。

    其次,避免使用额外的事件处理(例如 window.onload) 来得知页面是否已经准备好了。 

    第二种方式另一个选择是直接将 loadScript()函数嵌入在页面中,这可以避免另一次 HTTP 请求

    <script type="text/javascript"> 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_r("head")[0].appendChild(script);
    }
    loadScript("the-rest.js", function () {
        Application.init();
    });
    </script>

    关于loadScript()函数的封装:

       可以使用The YUI 3 approach

       LazyLoad 库

         LABjs库

     

    总结:

    管理浏览器中的 JavaScript 代码是个棘手的问题,因为代码执行阻塞了其他浏览器处理过程,诸如用户界面绘制。每次遇到<script>标签,页面必须停下来等待代码下载(如果是外部的)并执行,然后再继续处理页面其他部分。但是,有几种方法可以减少 JavaScript 对性能的影响:

    1、将所有<script>标签放置在页面的底部,紧靠 body 关闭标签</body>的上方。此法可以保证页面在脚本 运行之前完成解析。

    2、将脚本成组打包。页面的<script>标签越少,页面的加载速度就越快,响应也更加迅速。不论外部脚本 文件还是内联代码都是如此。

    3、有几种方法可以使用非阻塞方式下载 JavaScript:
      ——为<script>标签添加 defer 属性(只适用于 Internet Explorer 和 Firefox 3.5 以上版本)

      ——动态创建<script>元素,用它下载并执行代码
      ——用 XHR 对象下载代码,并注入到页面中

  • 相关阅读:
    Visual Studio 2010 Ultimate敏捷利剑:详解Scrum
    Microsoft .Net Micro Framework 3.0 and BIC Survey(2008 WinHEC)
    Visual Studio 2010 Ultimate开发与测试敏捷特性
    博客园开发征途又添新书《.NET软件设计新思维——像搭积木一样搭建软件》出版
    《运用Microsoft Visual Studio 2010落实敏捷软件开发》CSDN大会我的Session(PPT已上传)
    北京微软.Net和博客园俱乐部Open Party两本新书交流活动(已圆满结束)
    使用ASP.Net 3.5 的Ajax与Web服务开发实例
    WCF服务在JavaScript中使用ASP.NET的AJAX方法
    浅谈MVP与ModelViewViewModel(MVVM)设计模式
    荣获“微软2009最有影响力开发者”称号
  • 原文地址:https://www.cnblogs.com/liguwe/p/3958340.html
Copyright © 2011-2022 走看看