• 无阻塞加载脚本----性能优化(二)


    无阻塞加载脚本

    1  脚本阻塞并行下载

    行内脚本通过script标签引入整段javascript:

    <script>
        function displayMessage(msg){
            alert(msg);
    }
    </script>
    

      外部脚本通过script的src属性把独立文件中的JavaScript引入:

    <script src= "A.js"></script>

    src属性定义了需加载的外部URL,如果缓存中有脚本文件,浏览器就从缓存中读取,否则就发送HTTP请求获取。

     浏览器在下载和执行脚本时出现阻塞的原因:1  document.write改变了页面  2  其中一个js依赖于另一个js(浏览器要确保要确保脚本在HTML文档中出现的顺序来执行;否则可能会出现竞争状态;可以按顺序执行,但不一定要按顺序下载)。

    2  更好的运行脚本

      方案:1  把所有javascript内嵌到页面中(少量是可以的;由于通常页面大小和缓存能带来更多好处,因此推荐外部引入javascript)

      下面这些技术既可以避免因阻塞导致的减速影响,由拥有脚本的好处(可以并行运行脚本)。

       (1)XHR Eval。 

       (2)XHR注入(XHR Injection)。

         (3)Script in Iframe。

         (4)Script Dom Element。

       (5)Script Defer。

       (6)document.write Script Tag。

       XHR Eval (XMLHttpRequest(XHR)从服务端获取脚本;当响应完成时,通过eval命令执行内容)

      缺点:通过MLHttpRequest获取的脚本必须部署在和主页面相同的域中。以下是XH Eval相关代码:

    var xhrObj = getXHRObject();
    xhrObj.onreadystatechange = 
      function(){
        if ( xhrObj.readyState == 4 && 200 == xhrObj.status ){
          eval (xhrObj.responseText);
        } 
      };
      xhrObj.open("GET", 'A.js', true);//必须和主页面在·同一个域中
      xhrObj.send("");
    
      function getXHRObject() {
        var xhrObj = false;
        try{
          xhrObj = new XMLHttpRequest();
        }
        catch(e){
          var progid = ["MSXML2.XMLHTTP.5.0","MSXML2.XMLHTTP.4.0","MSXML2.XMLHTTP.3.0","MSXML2.XMLHTTP","Microsoft.XMLHTTP"];
          for( var i = 0;i< progid.length; ++i){
            try{
              xhrObj =  new ActiveXObject(progid[i]);
            }
            catch(e){
              continue;
            }
            break;
          }
        }
        finally {
          return xhrObj;
        }
      }
    

      XHR注入(通过创建一个script的DOM元素,然后把XMLHttpRequest的响应注入script中执行javascript;通过XMLHttpRequest获取的内容必须部署在和主页面相同的域中。)XHRInjection代码如下:

      var xhrObj = getXHRObject();
      xhrObj.onreadystatechange = 
        function (){
          if (xhrObj.readyState == 4 ){
            var scriptElem = document.createElement("script");
            document.getElementsByTagName('head')[0].appendChild(scriptElem);
            scriptElem.text = xhrObj.responseText;
          }
        };
        xhrObj.open ('GET', 'a.JS', true);
        xhrObj.send('');

       Script in Iframe

      iframe URL和主页面同域。即使主页面同域,我们任然要修改javascript来创建他们之间的关联。

      方案一:

      //使用“frames”访问主页面上的iframe

      window.frames[0].createNewDiv();

      //使用“getElementById”访问主页面上的iframe

      document.getElementById('frame').contentWindow.createNewDiv();

      方案二:

      //ifame使用parent变量引用父页面:

      //在iframe中使用“parent”访问主页面

      function createNewDiv(){

        var newDiv = parent.document.createElemnent('div');

        parent.document.body.appendChild(newDiv);

      }   

       //iframe自身的消耗比较高

      Script Dom Element

      相对于在HTML中使用script标签下载脚本文件而言,该技术使用JavaScript动态地创建script DOM 元素并设置src属性,这只要两三行javascript代码就可以实现。

      var scriptElem = document.createElement('script');

      scriptElem.src = 'http://anydomain.com/A.js' ;

      document.getElementByTagName('head')[0].appendChild(scriptElem);

      //这种方式下载脚本不会阻塞其它组件。允许跨域获取脚本。外部脚本可以直接调用。

      //script DOM Element    http://stevesouders.com/cuzillin/?ex=10010&title=Script+Dom+Element

      ,浏览器还有ScriptnDefer以及document.write ScriptTag 我这里就不一一介绍了。 

    3、浏览器忙指示器

      浏览器忙指示器,让用户感知到页面还在加载。浏览器忙指示器包括:状态栏、进度条、标签页图标和光标。

      另外两个浏览器忙指示器是组赛渲染和阻塞onload事件。缺点:当使用SCRIPT SRC技术下载脚本时,浏览器停止渲染所有脚本后面的内容。通常页面的onload事件要等到所有页面下载完时才会触发。如果让状态栏等待更长时间,才显示“完成”,并且默认输入框取焦点,影响用户体验。(忙指示器是否出发,是所使用的技术和浏览器共同决定的)

    4、确保(或避免)按顺序执行

      很多网页都包含多个有特定依赖顺序的脚本,它们会按照到达的顺序执行——最先到达,最先执行。这会导致竞争状态,进而导致未定义标识符错误。要想是浏览器按照顺序执行,而不是加载的顺序执行,可以使用Script Defer 和document.write ScriptTag保证脚本按照顺序执行。

      (脚本按照特定顺序执行并非总那么重要,有时候按照加载的顺序执行,可以快速的渲染页面。)

      不推荐使用document.write Script Tag技术。因为它只在部分浏览器中实现并行下载,而且还阻塞脚本之外所有其它资源的下载。Script Defer技术也只在部分浏览器中实现了并行下载。

      当脚本与主页面同域时,XHR Eval 、XHR 注入和Script in Iframe可以满足需求。但如果使用XHR Eval 或Script in Iframe技术,我们需要重构一部分脚本,而XHR注入和Script DOM Element技术可以直接使用现有的脚本文件,无需任何改动。

    5、最佳方案

        根据项目需求·合理选择最佳的技术。有下面六种情况:

      有不同域、无序

      不同域,保持顺序

      同域、无序、无忙指示器

      同域、无序、有忙指示器

      同域、保持顺序、无忙指示器

      同域、保持顺序、有忙指示器

      开发者可以通过该函数来确保按最佳方案加载脚本,原理如下:

      function loadScript(url, bPreserverOrder, bShowBusy);

  • 相关阅读:
    linux上修改系统默认语言设置
    【计算机基础之编程语言】编程语言的发展
    【Java语言特性学习之四】常用集合
    【Java语言特性学习之三】Java4种对象引用
    【Java语言特性学习之二】反射
    【网络知识之七】QUIC(http3)
    【网络知识之六】UDP
    【网络知识之五】TCP
    【网络知识之四】HTTP/2
    【网络知识之三】HTTPS协议
  • 原文地址:https://www.cnblogs.com/yaosusu/p/11275507.html
Copyright © 2020-2023  润新知