【高性能JavaScript】读书笔记 - 引入脚本(二) - 02


【简介】通过动态脚本的方式加载js脚本文件,利用其异步的过程实现了无阻塞脚本的效果,但是对于需要同步处理的脚本,就需要再将其同步化,或者采用我们之前的直接将脚本文件放在body尾部加载的方式。

1. 无阻塞的脚本(Noblocking Scripts)

减少JavaScript文件数量并限制HTTP请求的数量虽然能够提高加载效率,但随着Web应用的功能的丰富,所需要的JavaScript代码就越多,单个的JS文件也会使浏览器死锁一段时间。为了避免这种情况,我们需要向页面逐步加载JS文件,减少浏览器的阻塞。
通过这样的方式加载的脚本,我们称之为无阻塞的脚本(Noblocking Scripts)。

2. 动态脚本元素(Dynamic Script Elements)

通过DOM操作创建一个 <script> 标签的方式称之为动态脚本元素(Dynamic Script Elements)。
这种技术的重点在于:无论在合适启动下载脚本,文件的下载和执行都不会阻塞页面其他进程。

一般有以下三种方式实现:

第一种:document.write写入
document.write("<script src='package.js'><\/script>");

这种方法中document.write会重写页面,基本上不能用。

第二种:动态改变 <script> 的src属性
<script type="text/javascript" id="loadScript"></script>
<script type="text/javascript">
    loadScript = document.getElementById("loadScript");
    loadScript.src = 'package.js';
</script>

这种方式需要些两个<script> 标签,不符合我们上一讲中尽量减少<script> 标签数量的优化目标。

第三种:动态创建<script> 元素
<script type="text/javascript">
    var myScript = document.createElement('script');
    myScript.type = "text/javascript";
    myScript.src = "package.js";
    document.body.appendChild(myScript);
</script>

这种方式的动态脚本较优。

这三种方式都是异步的(脚本的加载不影响主页面程序继续往下执行),所以,如果当异步加载的脚本文件,会被主页面程序马上调用,就会无法正常执行。

比如,我们有一个package.js的脚本文件,里边有一个function,在这个函数中有一些代码,我们以一个alert弹框作为代码。

function packageFun(){
    alert("成功加载");
}

在另一个demo.html中,我们通过一个button来测试这个异步的过程。

<!DOCTYPE html>
<html>
<head>
<title>动态脚本</title>
<meta charset="utf-8">
<script type="text/javascript">
    function init(){
        var myScript = document.createElement('script');
        myScript.type = "text/javascript";
        myScript.src = "package.js";
        document.body.appendChild(myScript);
        document.write("<input type='button' value='测试运行效果' onclick='operation()'>");
        packageFun();
    }
    function operation() {
        packageFun();
    }
</script>
</head>
<body>
<input type="button" value="初始化加载" onclick="init()">
</body>
</html>

运行的结果是第一次点击button,没有alert出弹框,第二次点击document write出来的button,出现alert弹框。
原因在于,第一次点击button的时候,调用了init()方法,这个方法加载了script,这时就会引入package.js文件,在引入js文件的过程中,程序又继续执行,运行到packageFun()方法的时候,因为此时package.js文件还未加载完全,就找不到packageFun()这个方法(大家不要忘记packageFun()在package.js文件中),这个过程就是一个异步过程。
而第二次点击button的时候,执行packageFun()方法,因为在第一次点击button的时候,已经将package.js文件引入了,所以就能找到packageFUn()这个方法,所以就能alert出弹框。

如果遇到引入的js文件需要马上被调用,就需要将异步过程同步化,也就是让js文件完全加载后,再执行后面的代码。

<!DOCTYPE html>
<html>
<head>
<title>异步脚本同步化</title>
<meta charset="utf-8">
<script type="text/javascript">
    function loadScript(url, callback){
        var script = document.createElement('script');
        script.type = "text/javascript";

        if (script.readyState) {
            // 判断是IE浏览器
            alert("IE浏览器");     
            script.onreadystatechange = function(){
                if (script.readyState == "loaded" || script.readyState == "complete") {
                    script.onreadystatechange = null;
                    callback();
                }
            }
        } else {
            // 判断是其他浏览器
            alert("其他浏览器");
            script.onload = function() {
                callback();
            }
        }

        script.src = url;
        document.getElementsByTagName('head')[0].appendChild(script);
    }

    loadScript("package.js", function(){
        packageFun();
    });
</script>
</head>
<body>
</body>
</html>

这段代码中,关于对IE兼容性处理的部分不做过多介绍,如果对这部分不太了解的同学,可以百度一下相关的内容。

这段代码的核心在于,封装的loadScript()方法,通过监听脚本js文件完全加载的事件后,再执行callback回调函数中的内容,而要执行package.js文件中的内容,就放在这个回调函数中,模拟实现了先加载完全脚本文件,后执行callback函数中的代码的过程。

参考资料:
[1]js动态加载脚本(http://www.cnblogs.com/zhuimengdeyuanyuan/archive/2013/03/06/2946277.html)

附: 欢迎大家关注我的新浪微博 - 一点编程,了解最新动态 。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值