• 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>
  • 相关阅读:
    sqlplus时报Linux-x86_64 Error: 13: Permission denied
    thrift之TTransport层的缓存传输类TBufferedTransport和缓冲基类TBufferBase
    Java实现 蓝桥杯 算法提高 新建Microsoft world文档
    Java实现 蓝桥杯 算法提高 新建Microsoft world文档
    Java实现 蓝桥杯 算法提高 快乐司机
    Java实现 蓝桥杯 算法提高 快乐司机
    Java实现 蓝桥杯 算法提高 队列操作
    Java实现 蓝桥杯 算法提高 队列操作
    Java实现 蓝桥杯 算法提高 文本加密
    Java实现 蓝桥杯 算法提高 合并石子
  • 原文地址:https://www.cnblogs.com/susanws/p/5441544.html
Copyright © 2020-2023  润新知