5种JavaScript脚本加载的方式


Posted in Javascript onJanuary 16, 2017

javaScript文件(下面简称脚本文件)需要被HTML文件引用才能在浏览器中运行。在HTML文件中可以通过不同的方式来引用脚本文件,我们需要关注的是,这些方式的具体实现和这些方式可能会带来的性能问题。

当浏览器遇到(内嵌)<script>标签时,当前浏览器无从获知javaScript是否会修改页面内容。因此,这时浏览器会停止处理页面,先执行javaScript代码,然后再继续解析和渲染页面。同样的情况也发生在使用 src 属性加在javaScript的过程中(即外链 javaScript),浏览器必须先花时间下载外链文件中的代码,然后解析并执行它。在这个过程中,页面渲染和用户交互完全被阻塞了。

也就是说:每当浏览器解析到<script>标签(无论内嵌还是外链)时,浏览器会(一根筋地)优先下载、解析并执行该标签中的javaScript代码,而阻塞了其后所有页面内容的下载和渲染。

方式一:惯例的做法

最传统的方式是在head标签内插入<script>标签。

然而这种常规的做法却隐藏着严重的性能问题。根据上述对<script>标签特性的描述,我们知道,在该示例中,当浏览器解析到<script>标签时,浏览器会停止解析其后的内容,而优先下载脚本文件,并执行其中的代码,这意味着,其后的test.css样式文件和<body>标签都无法被加载,由于<body>标签无法被加载,那么页面自然就无法渲染了。因此在该javaScript代码完全执行完之前,页面都是一片空白。

<script type="text/javaScript" src="example.js"></script>

方式二:经典的做法

既然<script>标签会阻塞其后内容的加载,那么将<script>标签放到所有页面内容之后不就可以避免这种糟糕的状况了吗? 将所有的<script>标签尽可能地放到<body>标签底部,以尽量避免对页面其余部分下载的影响。

在IE8+浏览器上已经实现了脚本并行下载,但在某些浏览器中(即使脚本文件放到了<body>标签底部),页面中脚本仍是一个接着一个加载的。所以我们需要下一个方法,即:动态加载脚本。

方式三:动态脚本

通过文档对象模型(DOM),我们可以几乎可以页面任意地方创建。

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

上述代码动态创建了一个外链file1的<script>标签,并将其添加到<head>标签内。这种技术的重点在于:

无论在何时启动下载,文件的下载和执行过程不会阻塞页面其他进程(包括脚本加载)。
然而这种方法也是有缺陷的。这种方法加载的脚本会在下载完成后立即执行,那么意味着多个脚本之间的运行顺序是无法保证的(除了Firefox和Opera)。当某个脚本对另一个脚本有依赖关系时,就很可能发生错误了。比如,写一个jQuery代码,需要引入jQuery库,然而你写的jQuery代码文件很可能会先完成下载并立即执行,这时浏览器会报错——‘jQuery未定义'之类的,因为此时jQuery库还未下载完成。于是做出以下改进:

<script type='text/javascript'>
  function loadScript(url, callback) {
    var script = document.createElement('script');
    script.type = "text/javaScript";
    // IE和opera支持onreadystatechange
    // safari、chrome、opera支持onload
    if (script.readyState) {//IE
      script.onreadystatechange = function() {
        if (script.readyState == "loaded"
            || script.readyState == "complete") {
          script.onreadystatechange = null;
          callback();
        }
      };
    } else {//其他浏览器
      script.onload = function() {
        callback();
      };
    }
    script.src = url;
    document.getElementsByTagName('head')[0].appendChild(script);
  }
</script>

上述代码改进的地方就是增加了一个回调函数,该函数会在相应脚本文件加载完成后被调用。这样便可以实现顺序加载了,写法如下(假设file2依赖file1,file1和file3相互独立):

loadScript(‘file1.js',function(){ loadScript(‘file2.js',function(){}); }); loadScript(‘file3.js',function(){});

file2会在file1加载完后才开始加载,保证了在file2执行前file1已经准备妥当。而file1和file3是并行下载的,互不影响。 虽然loadScript函数已经足够好,但还是有些不尽人意的地方——通过分析这段代码,我们知道,loadScript函数中的顺序加载是以脚本的阻塞加载来实现的(正如上述红字部分指出的那样)。而我们真正想实现的是——脚本同步下载并按相应顺序执行,即并行加载并顺序执行。

方式四:LABjs

LABjs库能帮我们真正地实现“并行加载与顺序执行”,推荐写法如下:

<script src="LAB.js"></script>
<script type="text/javaScript">

$LAB


 .script("script1.js").wait()


 .script("script2-a.js")


 .script("script2-b.js")


 .wait(function(){



 initScript1();



 initScript2();


 })


 .script("script3.js")


 .wait(function(){



 initScript3();


 });
</script>

方式五:requireJS

<script src="require.js"></script>
<script type="text/javaScript">

require([



"script1.js",



"script2-a.js",



"script2-b.js",



"script3.js"


 ],


 function(){



initScript1();



initScript2();



initScript3();


 }


);
</script>

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
基于jquery的图片的切换(以数字的形式)
Feb 14 Javascript
Javascript selection的兼容性写法介绍
Dec 20 Javascript
Javascript正则控制文本框只能输入整数或浮点数
Sep 02 Javascript
运行Node.js的IIS扩展iisnode安装配置笔记
Mar 02 Javascript
javascript实现框架高度随内容改变的方法
Jul 23 Javascript
jQuery元素属性操作实例(设置、获取及删除元素属性)
Sep 08 Javascript
jquery实现文字单行横移或翻转(上下、左右跳转)
Jan 08 Javascript
Angular.js项目中使用gulp实现自动化构建以及压缩打包详解
Jul 19 Javascript
vue 下列表侧滑操作实例代码详解
Jul 24 Javascript
JavaScript实现淘宝京东6位数字支付密码效果
Aug 18 Javascript
three.js实现圆柱体
Dec 30 Javascript
vue自动路由-单页面项目(非build时构建)
Apr 30 Javascript
WebPack基础知识详解
Jan 16 #Javascript
jquery Ajax 全局调用封装实例详解
Jan 16 #Javascript
javascript循环链表之约瑟夫环的实现方法
Jan 16 #Javascript
函数四种调用模式以及其中的this指向
Jan 16 #Javascript
js实现导航栏中英文切换效果
Jan 16 #Javascript
Bootstrap面板使用方法
Jan 16 #Javascript
codeMirror插件使用讲解
Jan 16 #Javascript
You might like
php微信公众号开发之二级菜单
2018/10/20 PHP
PHP数字金额转换成中文大写显示
2019/01/05 PHP
使用laravel和ajax实现整个页面无刷新的操作方法
2019/10/03 PHP
laravel与thinkphp之间的区别与优缺点
2021/03/02 PHP
推荐自用 Javascript 缩图函数 (onDOMLoaded)……
2007/10/23 Javascript
JavaScript 弹出窗体点击按钮返回选择数据的实现
2010/04/01 Javascript
jQuery与其它库冲突的解决方法
2010/06/25 Javascript
Jquery中offset()和position()的区别分析
2015/02/05 Javascript
jquery中JSON的解析方式
2015/03/16 Javascript
根据user-agent判断蜘蛛代码黑帽跳转代码(js版与php版本)
2015/09/14 Javascript
如何使用AngularJs打造权限管理系统【简易型】
2016/05/09 Javascript
jstl中判断list中是否包含某个值的简单方法
2016/10/14 Javascript
vue.js学习笔记之绑定style样式和class列表
2016/10/31 Javascript
JavaScript实现反转字符串的方法详解
2017/04/27 Javascript
jQuery DOM节点的遍历方法小结
2017/08/15 jQuery
React-Native之定时器Timer的实现代码
2017/10/04 Javascript
React router动态加载组件之适配器模式的应用详解
2018/09/12 Javascript
如何在JavaScript中优雅的提取循环内数据详解
2019/03/04 Javascript
python实现数通设备tftp备份配置文件示例
2014/04/02 Python
Python正则表达式分组概念与用法详解
2017/06/24 Python
python pycurl验证basic和digest认证的方法
2018/05/02 Python
详解Django中六个常用的自定义装饰器
2018/07/04 Python
python django框架中使用FastDFS分布式文件系统的安装方法
2019/06/10 Python
tensorflow 2.1.0 安装与实战教程(CASIA FACE v5)
2020/06/30 Python
Python3 ffmpeg视频转换工具使用方法解析
2020/08/10 Python
python 爬虫请求模块requests详解
2020/12/04 Python
澳大利亚冒险体验:Adrenaline(跳伞、V8赛车、热气球等)
2017/09/18 全球购物
Gretna Green中文官网:苏格兰格林小镇
2019/10/16 全球购物
如果重写了对象的equals()方法,需要考虑什么
2014/11/02 面试题
建筑工程自我鉴定
2013/10/18 职场文书
仓管员岗位责任制
2014/02/19 职场文书
村党支部换届选举方案
2014/05/02 职场文书
作弊检讨书
2015/01/27 职场文书
爱国教育主题班会
2015/08/14 职场文书
解决IDEA翻译插件Translation报错更新TTK失败不能使用
2022/04/24 Python
Android学习之BottomSheetDialog组件的使用
2022/06/21 Java/Android