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

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

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

五种引用脚本的方式:

1.惯例的做法

2.经典的做法

3.动态脚本

4.LABjs

5.requireJS

==惯例的做法

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

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

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

==经典的做法

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

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

==动态脚本

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

var script=document.createElement(‘script’);

script.type=’text/javaScript’;

script.src=’file1.js’;

document.getElementsByTagName(‘head’)[0].appendChild(script);

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

无论在何时启动下载,文件的下载和执行过程不会阻塞页面其他进程(包括脚本加载)。

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

function loadScript(url,callback){

var script=document.createElement(‘script’);

script.type=”text/javaScript”;

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);

}

上述代码改进的地方就是增加了一个回调函数,该函数会在相应脚本文件加载完成后被调用。这样便可以实现顺序加载了,写法如下(假设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>

 

js的并行加载与顺序执行的更多相关文章

  1. js的并行加载以及顺序执行

    重新温习了下这段内容,发现各个浏览器的兼容性真的是搞大了头,处理起来很是麻烦. 现在现总结下并行加载多个js的方法: 1,对于动态createElement('script')的方式,对所有浏览器都是 ...

  2. js并行加载,顺序执行

    js并行加载,顺序执行 <script>运行脚本或加载外部文件时,会阻塞页面渲染,阻塞其他资源的加载.如果页面中需要加载多个js文件,在古老浏览器中性能会比较糟糕. 因此有了最原始的优化原 ...

  3. 动态加载JS文件,并根据JS文件的加载状态来执行自己的回调函数

    动态加载JS文件,并根据JS文件的加载状态来执行自己的回调函数, 在很多场景下,我们需要在动态加载JS文件的时候,根据加载的状态来进行后续的操作,需要在JS加载成功后,执行另一方法,这个方法是依托在加 ...

  4. JS,Javascript加载与函数执行过程

    Js,Javascript加载与函数执行过程 test.html <!DOCTYPE HTML> <html lang="en"> <head> ...

  5. js中页面加载完成后执行的几种方法及执行顺序

    在js和jquery使用中,经常使用到页面加载完成后执行某一方法.通过整理,大概是五种方式(其中有的只是书写方式不一样). 1:使用jQuery的$(function){}; 2:使用jquery的$ ...

  6. js 文档加载完成之后执行 备用

    //文档加载完成之后执行 (function(){ var _globeCallback; window.$$ = function(callback){ _globeCallback = callb ...

  7. js中页面加载完成后执行的几种方式及执行顺序

    1:使用jQuery的$(function){}; 2:使用jquery的$(document).ready(function(){});前两者本质上没有区别,第1种是第2种的简写方式.两个是docu ...

  8. requirejs:性能优化-及早并行加载

    为了提高页面的性能,通常情况下,我们希望资源尽可能地早地并行加载.这里有两个要点,首先是尽早,其次是并行. 通过data-main方式加载要尽可能地避免,因为它让requirejs.业务代码不必要地串 ...

  9. js顺序加载与并行加载

    前端优化过程中常提到js的加载方式,下面说下几种常用的加载方式: 1:head标签内插入<script>标签 <script type="text/javaScript&q ...

随机推荐

  1. samsung Galaxy s2(GT i9100g )刷机升级至4.4小记

    从昨天上午到现在,大部分时间都是在将i9100g更新到4.4.虽然中途也做了一些别的事情,但是更新过程还是走了一点弯路,比开始预想的稍微慢了一点,现在将完整的更新步骤分享给大家,以帮助后来的同学.升级 ...

  2. HTML 学习笔记 CSS样式(简介和语法)

    CSS概述 CSS指层叠样式表(Cascading Style Sheets) 样式定义如何显示HTML元素 样式通常存储在样式表中 把样式添加到HTML4.0中 是为了解决内容与表现分离的问题 外部 ...

  3. java工程中的.classpath<转载>

    第一部分:classpath是系统的环境变量,就是说JVM加载类的时候要按这个路径下去找,当然这个路径下可以有jar包,那么就是jar包里所有的class. eclipse build path是ec ...

  4. [转]Linux后台进程管理利器:supervisor

    FROM : http://www.liaoxuefeng.com/article/0013738926914703df5e93589a14c19807f0e285194fe84000 Linux后台 ...

  5. 清北学堂2017NOIP冬令营入学测试P4747 D’s problem(d)

    时间: 1000ms / 空间: 655360KiB / Java类名: Main 背景 冬令营入学测试题 描述 题目描述 小D是一名魔法师,它最喜欢干的事就是对批判记者了. 这次记者招待会上,记者对 ...

  6. 用C++和shell获取本机CPU、网卡IO、内存、磁盘等的基本信息

    用C++和shell获取本机CPU.网卡.内存.磁盘等的基本信息: 由于对C++相关的函数没多少了解,但是觉得用shell反而相对简单一些: 一.shell脚本,用来辅助C++获取主机的资源使用信息 ...

  7. SQL 性能调优日常积累

    我们要做到不但会写SQL,还要做到写出性能优良的SQL,以下为笔者学习.摘录.并汇总部分资料与大家分享! (1)选择最有效率的表名顺序(只在基于规则的优化器中有效) ORACLE 的解析器按照从右到左 ...

  8. <实训|第五天>通过搭建NFS,FTP实现共享文件附Vim脚本游戏

    先说个事情:我周末是不更新这个系列教程的,不过其他内容的会更新,我周末就整理这一周的各种内容到我的微信公众号中,提供给大家! 期待已久的linux运维.oracle"培训班"终于开 ...

  9. ASP.NET - SqlSugar ORM框架 更新列表

    以后SqlSugar所有更新都会在这个贴子更新 SqlSugar是一款轻量级的MSSQL ORM ,除了具有媲美ADO的性能外还具有和EF相似简单易用的语法. 学习列表 0.功能更新 1.SqlSug ...

  10. OS存储器管理(三) 虚拟存储器

    基本概念与实现 1)局部性原理 在一段时间内,运行的作业程序仅访问(涉及到)一部分作业代码,即不会涉及整个地址空间.即在一段时间间隔内,仅装入一部分代码,作业照样能正常运行 2)虚拟存储器的引入 作业 ...