关于js执行顺序和jquery.html

下面这些知识虽然是前端相关的,但是做为一个想深入web的人,还是非常有必要知道的。很多时候当前端跟你抱怨为什么我的js中明明声明了变量,但还报未定义的错;为什么我写一个alert调试就好了?很有可能就是下面所提到的问题。

1 js为什么不按代码中的次序执行了?

正常的html中外联script,script无法并行下载,阻塞后面其他资源的下载;且执行顺序可以得到保证(新版本浏览器有改进,可以并行下载js,执行顺序也会保证)。所以我们一般在html中写的js都没有问题,但问题是,这个会影响整个网页相关资源下载速度。

鉴于此,人们又想了很多方法来“欺骗”浏览器,以达到加速下载js和相关资源文件的目的,方法大概有以下几种:

  • XHR Eval :ajax获得js内容,然后执行
  • XHR Injection : ajax获得js内容,然后创建一个script的node,插入到文档dom tree中
  • Script in Iframe : iframe src为js文件
  • Script DOM Element :动态创建script,然后设置其src
  • Script Defer : script标签加入 defer属性
  • document.write Script Tag :document.write("<script type='text/javascript' src='A.js'><\/script>");

既然可以并行下载,那么执行顺序就是一个需要确认的问题了,可惜的是,不是每种技术都能保证脚本执行的次序。具体情况可以参考下表(节选自 《Even Faster Web Sites》):

2 jquery的html函数好像有时候也不灵啊!

假设我们如此调用:

$('#content').html(data);

jquery 的html函数使用同步ajax下载data中的外联js。对于inline的js,执行Script DOM Element在head节点插入一个script节点。

从上面的分析来看,data中js的执行顺序是可以保证的。但有时调用jquery.html,却仍然出现执行顺序混乱的情形,原因是外联的js是不同的域。由于ajax无法跨域,故这时候无法通过同步ajax下载来加入外联js,而是通过和内联js一样的方式:将外联的js以Script DOM Element 的方式插入到head节点。按照上面的图,执行顺序是无法在所有浏览器上保证的(ensures order)。

解决方法: 在调用jquery.html前,使用 document.write Script Tag将外联的js载入。

3 文章开头提到的问题

外联js定义了js变量,但还报undefined错:很有可能就是执行顺序不对,执行使用变量的代码时,定义的js虽然在前面,但还没有下载完呢。

alert一下,一切就是好的了:还是一个道理,定义的外联js没有下载完成,同时,你可以试试setTimeout,将你使用外联js的变量的代码晚点执行,也会是好的。

4 参考资料

下面这些资料,非常值得一读:

  • 《Even Faster Web Sites》
  • http://www.cnblogs.com/sanshi/archive/2011/02/28/1967367.html
  • http://www.cnblogs.com/sanshi/archive/2011/03/01/1968275.html
  • http://www.cnblogs.com/sanshi/archive/2011/03/02/1969224.html

- to blog -

blog built using the cayman-theme by Jason Long. LICENSE