zoukankan      html  css  js  c++  java
  • javascript笔记——js的阻塞特性[转载]

    JS具有阻塞特性,当浏览器在执行js代码时,不能同时做其它事情,即<script>每次出现都会让页面等待脚本的解析和执行(不论JS是内嵌的还是外链的),JS代码执行完成后,才继续渲染页面。

    由于,JS的这种阻塞特性,每次遇到<script>,页面都必须停下来等待脚本下载并执行,这会停止页面绘制,带来不好的用户体验。所以,有必要减少JS阻塞特性造成的困扰。

    1 优化脚本位置

    HTML4规范中,<script>可以放在<head>或<body>中。你可能习惯性的在<head>中放置多个外链JS、CSS,以求优先加载它们。浏览器在继续到<body>之前,不会渲染页面,所以,把JS放在<head>中,会导致延迟。为了提高用户体验,新一代浏览器都支持并行下载JS,但是JS下载仍然会阻塞其它资源的下载(eg.图片)。尽管脚本的下载过程并不会相互影响,但页面仍然必须等待所有JS下载并执行完成才能继续。显见,所有<script>应该尽可能放到<body>的底部,以减少对页面下载的影响。

    注意:CSS文件本身是并行下载,不会阻塞页面的其他进程。但是,如果把一段内嵌脚本放在引用外链CSS的<link>之后会导致页面阻塞去等待CSS的下载。这样做是为了确保内嵌脚本在执行时能够获得正确的样式信息。所以,最好不要把内嵌脚本放在CSS的<link>之后。

    2 减少外链脚本数量以改善性能

     原因很简单,额外的HTTP请求会带来额外的开销,所以减少页面中外链脚本的数量,有助于改善性能。

    3 使用无阻塞下载JS方法

    无阻塞脚本的秘诀在于,在页面加载完成后才加载JS,即在window对象的load事件触发后在下载脚本。

    3.1 使用<script>的defer属性(仅IE和Firefox3.5以上);

    defer属性指明本元素所含的脚本不会修改DOM,因此代码能安全的延迟执行。defer属性的<script>,对应的JS文件将在页面解析到<script>时开始下载,但并不会执行,直到DOM加载完成,即onload事件触发前被调用。当一个带有defer属性的JS文件下载时,他不会阻塞浏览器的其它进程,因此这类文件可以与页面中的其他资源并行下载。

    复制代码
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <title>DeferredScripts</title>
    </head>
    <body>

    <script type="text/javascript" defer>
    alert("defer");
    </script>

    <script type="text/javascript">
    alert("script");
    </script>

    <script type="text/javascript">
    window.onload = function() {
    alert("load");
    };
    </script>

    </body>
    </html>
    复制代码

    对于支持defer的浏览器弹出顺序是:script>defer>load;而不支持该属性的浏览器的弹出顺序为:defer>script>load。

    3.2 使用动态创建的<script>元素来下载并执行代码

    实例代码如下:

    复制代码
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <title>DynamicScriptElements</title>
    </head>
    <body>

    <script type="text/javascript">
    function loadScript(url, callback) {
    var script = document.createElement("Script");
    script.type = "text/javascript";

    //IE 验证脚本是否下载完成
    if (script.readyState) {
    script.onreadystatechange = function() {
    //readyState属性有5种取值
    //uninitialized:初始状态
    //loading:开始下载
    //interactive:数据完成下载但尚不可用
    //complete:数据已经准备就绪
    //实际使用时,readyState的值并不像我们预想的那样有规律,实践发现使用readyState
    //最靠谱的方式是同时检查以下2个状态,只要其中1个触发,就认为脚本下载完成。
    if (script.readyState == "loaded" || script.readyState == "complete") {
    //移除事件处理器,确保事件不会处理2次
    script.onreadystatechange = null;
    callback();
    }
    };
    }

    //其他浏览器
    else {
    script.onload = function() {
    callback();
    };
    }

    script.src = url;
    //把新建的<Script>添加到<head>里比添加到<body>里更保险。
    document.getElementsByTagName("head")[0].appendChild(script);
    }

    //动态加载多个JS文件
    //优先加载Common.js,等待Common.js加载完毕后加载Costom.js
    //不同浏览器的执行顺序不同
    //Firefox、Opera能够保证按照你脚本的加载顺序来执行
    //其他浏览器会按照从服务端返回的顺序执行代码,因此使用嵌套的方法保证调用顺序
    loadScript("Common.js", function() {
    loadScript("Costom.js", function() {
    alert("all load");
    });
    });
    </script>

    </body>
    </html>
    复制代码

    文件在该元素被添加到页面时开始下载。这种技术的重点在于:无论在何时启动下载,文件的下载与执行不会阻塞页面的其他进程。使用动态脚本节点下载文件时,根据浏览器不同,多数浏览器,返回的代码会立即执行(Firefox、Opera,会等待此前所有动态节点执行完毕)。当脚本”自执行“时,这种机制运行正常,但是当代码内只包含供其它脚本调用的接口时,就必须确保脚本下载完成并准备就绪,在上例中列举了不同浏览器的验证方法。

    注意:如果多个文件的顺序很重要,更好的做法是把它们按正确顺序合并为一个文件。此外,说把新建的<Script>添加到<head>里比添加到<body>里更保险是因为要尽量避免页面报错(在低版本的IE中使用不当会发生"操作已中止"错误

    3.3 使用XHR对象下载JS代码并注入页面中

    实例代码如下:

    复制代码
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <title>XhrScriptInjection</title>
    </head>
    <body>

    <script type="text/javascript">
    var xhr = new XMLHttpRequest();
    xhr.open("get", "JScript.js", true);
    xhr.onreadystatechange = function() {
    if (xhr.readyState == 4) {
    //2XX表示有效响应,304表示从缓存读取
    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); //一旦新创建的<script>被添加到页面,代码就立刻执行然后准备就绪。
    }
    }
    };
    xhr.send(null);
    </script>

    </body>
    </html>
    复制代码

    这种方法的优点是,你可以下载JS代码但不立即执行。由于代码是在<script>标签之外返回的,因此它下载后不会自动执行,这使得你可以把脚本的执行推迟到你准备好的时候。另一个优点是,同样的代码在所有主流浏览器中都能正常工作。

    这种方法的主要局限性是JS文件必须与所有请求的页面处于相同的域。
    综上所述,向页面中添加大量JS的推荐做法只需两步:先添加动态加载的所需代码,然后加载初始化页面所需的剩下代码。

    复制代码
        <script type="text/javascript" src="Common.js"></script>

    <script type="text/javascript">
    loadScript("Costom.js", function() {
    //Do Something
    });
    </script>
    复制代码

    优化前:

    优化后:

    "操作已中止"错误
    复制代码
    <html>
    <head>
    <title>Operation Aborted Example</title>
    </head>
    <body>
    <p>The following code should cause an Operation Aborted error in IE versions prior to 8.</p>
    <div>
    <script type="text/javascript">
    document.body.appendChild(document.createElement("div"));
    </script>
    </div>
    </body>
    </html>
    复制代码

    上述代码在低版本IE中会报"操作已中止"错误。出现此问题的原因是子容器 HTML 元素包含试图修改父容器元素的子容器的脚本。脚本试图使用 innerHTML 方法或 appendChild 方法修改父容器元素。例如对于如果 DIV 元素是一个 BODY 元素中的子容器,并且在 DIV 元素中的一个 SCRIPT 块试图修改 DIV 元素的父容器的 BODY 元素可能会出现此问题。

    最简单的解决方法:将脚本移到body元素的范围。

    复制代码
    <html>
    <head>
    <title>Operation Aborted Example</title>
    </head>
    <body>
    <p>The following code should cause an Operation Aborted error in IE versions prior to 8.</p>
    <div>
    </div>
    <script type="text/javascript">
    document.body.appendChild(document.createElement("div"));
    </script>
    </body>
    </html>
    复制代码

    其它解决方法可以参考:

    http://www.nczonline.net/blog/2008/03/17/the-dreaded-operation-aborted-error

    http://support.microsoft.com/kb/927917/zh-cn

    作者:MeteorSeed

    感谢您阅读本文,如果您觉得有所收获,麻烦点一下右边的“推荐”,您的支持是对我最大的鼓励...

    转载请注明出处。

  • 相关阅读:
    第08组 Alpha冲刺(1/4)
    第08组 团队Git现场编程实战
    第二次结对编程作业
    团队项目-需求分析报告
    团队项目-选题报告
    第一次结对编程作业
    第一次个人编程作业
    第一次实践作业
    互联网协议学习笔记
    【选修建模的小练习】长方形椅子的稳定性探究
  • 原文地址:https://www.cnblogs.com/MonaSong/p/5313228.html
Copyright © 2011-2022 走看看