不得不说的JavaScript异步加载(2)

this is a test <script type="text/javascript" src='https://china-addthis.googlecode.com/svn/trunk/addthis.js' async='async'></script> <script type="text/javascript" src='https://libs.baidu.com/jquery/2.0.0/jquery.min.js'></script> <script type="text/javascript"> console.log('hello world'); </script>

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

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

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

this is a test <script type="text/javascript" src='https://china-addthis.googlecode.com/svn/trunk/addthis.js' defer='defer'></script> <script type="text/javascript" src='https://libs.baidu.com/jquery/2.0.0/jquery.min.js'></script> <script type="text/javascript"> console.log('hello world'); </script>

  似乎实现效果差不多,但是真的一样吗?我们来看看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 在网络读取(下载)这块儿是一样的,都是异步的(相较于 HTML 解析)

它俩的差别在于脚本下载完之后何时执行,显然 defer 是最接近我们对于应用脚本加载和执行的要求的

关于 defer,此图未尽之处在于它是按照加载顺序执行脚本的,这一点要善加利用

async 则是一个乱序执行的主,反正对它来说脚本的加载和执行是紧紧挨着的,所以不管你声明的顺序如何,只要它加载完了就会立刻执行

仔细想想,async 对于应用脚本的用处不大,因为它完全不考虑依赖(哪怕是最低级的顺序执行),不过它对于那些可以不依赖任何脚本或不被任何脚本依赖的脚本来说却是非常合适的,最典型的例子:Google Analytics

  

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

this is a test <script type="text/javascript" src='https://china-addthis.googlecode.com/svn/trunk/addthis.js' defer='defer'></script> <script type="text/javascript" src='https://libs.baidu.com/jquery/2.0.0/jquery.min.js' defer='defer'></script> <script type="text/javascript" src='https://www.linuxidc.com/index.js' defer='defer'></script>

console.log('hello world');

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

总结

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

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

高性能JavaScript编程(高清PDF原版)及中英文对照版 PDF 

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/985b8d3bd37dfa2ae2f2178846de9bd6.html