设为首页 加入收藏

TOP

不得不说的JavaScript异步加载
2015-08-31 21:24:32 来源: 作者: 【 】 浏览:39
Tags:不得 不说 JavaScript 异步 加载

  默认的js是同步加载的,这里的“加载”可以理解成是解析、执行,而不是“下载”,在最新版本的浏览器中,浏览器对于代码请求的资源都是瀑布式的加载,而不是阻塞式的,但是js的执行总是阻塞的。这会引起什么问题呢?如果我的index页面要加载一些js,但是其中的某个请求迟迟得不到响应,于是阻塞了后面的js代码的执行(同步加载),同时页面渲染也不能继续(如果js引入是在head标签后)。


  比如上面的这段代码,保存为index.html文件,页面的主体是一个简单的字符串,但是代码执行后页面迟迟都是空白,为何?因为请求的js迟迟无法加载(可能由于谷歌被墙等原因),于是阻塞了后面的代码的执行,页面得不到渲染。可能你会提议,把js代码放到前不就能先渲染页面了!好方法,我们尝试着将js放后面:


  页面瞬间被渲染,“this is a test"也很快出现在前台,世界似乎平静了,可是:


  在前面代码的基础上简单加了一段代码,但是"hello world"迟迟无法在控制台输出,显然前面的js请求阻塞了后面代码的加载,我们恍然大悟,改变js的加载位置只能改变页面的渲染,然而对于js的加载并没有什么卵用,js还是会阻塞。


  我们的要求似乎很简单,能在页面加载的同时,在控制台输出字符串即可,再讲的通俗一点,就是在请求第一段谷歌提供的js的同时,继续执行下面的js,也就是实现js的异步加载。


  最常见的做法是动态生成script标签:


  但是还是有点问题,这种加载方式在加载执行完之前会阻止 onload 事件的触发,而现在很多页面的代码都在 onload 时还要执行额外的渲染工作等,所以还是会阻塞部分页面的初始化处理:


  比如上面的代码不能很好地渲染”hello world”,我们只需将注释去掉就可以了,让谷歌提供的js在onload 时才开始异步加载。这样就解决了阻塞 onload 事件触发的问题。


  补充DOMContentLoaded 与 OnLoad 事件 ? DOMContentLoaded : 页面(document)已经解析完成,页面中的dom元素已经可用。但是页面中引用的图片、subframe可能还没有加载完。 OnLoad:页面的所有资源都加载完毕(包括图片)。浏览器的载入进度在这时才停止。这两个时间点将页面加载的timeline分成了三个阶段。


  以上似乎能较好解决这个问题,但是html5提供了更简便的方法,async属性!


  async是html5的新属性,async 属性规定一旦脚本可用,则会异步执行(一旦下载完毕就会立刻执行)。


  需要注意的是async 属性仅适用于外部脚本(只有在使用 src 属性时)


  defer属性常常和async一起提起:


  似乎实现效果差不多,但是真的一样吗?我们来看看defer属性的定义。


  以前的defer只支持ie的hack,现在html5的出现开始全面支持defer。defer 属性规定当页面已完成加载后,才会执行脚本。defer 属性仅适用于外部脚本(只有在使用 src 属性时)。ps:ie支持的defer似乎并非如此,因为对ie无感,不深究,有兴趣的可以去查阅相关资料。


  既然async和defer经常一起出现,那么辨析一下吧!


  如果没有async和defer属性(赋值为true,下同),那么浏览器会立即执行当前的js脚本,阻塞后面的脚本;如果有async属性,加载和渲染后续文档元素的过程将和当前js的加载与执行并行进行(异步);如果有defer属性,那么加载后续文档元素的过程将和 script.js 的加载并行进行(异步),但是 script.js 的执行要在所有元素(DOM)解析完成之后,DOMContentLoaded 事件触发之前完成。


  来看一张网上盗的图:



  蓝色线代表网络读取,红色线代表执行时间,这俩都是针对脚本的;绿色线代表 HTML 解析。


  此图告诉我们以下几个要点(摘自defer和async的区别):


  


  但是在我看来(以下个人理解,如有出入还望指出),defer在异步加载上的应用并不会比async广。async的英文解释是异步,该属性作用在脚本上,使得脚本加载(下载)完后随即开始执行,和动态插入script标签作用类似(async只支持h5,后者能兼容浏览器);而defer的英文解释是延迟,作用也和字面解释类似,延迟脚本的执行,使得dom元素加载完后才开始有序执行脚本,因为有序,所以会带来另一个问题:


  如果执行这段代码,控制台的“hello world”也会迟迟得不到结果。所以我觉得还是async好用,如果要考虑依赖的话,可以选择requirejs、seajs等模块加载器。


  java script的异步加载还有一些方式,比如:AJAX eva l(使用AJAX得到脚本内容,然后通过eva l(xmlhttp.responseText)来运行脚本)、iframe方式等。


  以上理解如果有出入,还望指出~


】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇高性能JavaScript 加载和执行 下一篇高性能JavaScript编程(高清PDF原..

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: