最近在工作中遇到了一些script方面的加载顺序问题,下面进行一些介绍
在之前的理解中,浏览器是作为一个解释器,逐行分析代码,构建DOM树,然后进行资源加载的,那么如果在一个script执行过程中document.write一个新的script标记到文档流中,本script执行完毕后,浏览器就会同步执行新的script中的脚本资源。
那如果是通过document.createElement("script")的方式,然后动态加载到document head里面去的呢,这个被称为异步脚本加载机制,会异步地发出一个新的请求,然后在收到返回结果时候进入浏览器执行队列,开始执行,所以说这个的执行机制是不确定的,可能在下面的同步脚本任意一个之前,或者之后。举例:
后端的c1.php c3.php c5.php分别代表延时 1秒 3秒 5秒返回结果,再返回时候会分别打印 1111111 333333333 55555555
<script> var t = document.createElement("script"); t.src="c1.php"; document.head.appendChild(t); </script> <script src="c3.php"></script>
这个显示的结果是
11111111
3333333
这个是在c1是一个异步的请求,而c3是一个同步的请求,同步的请求和异步的资源加载请求都发出后,1秒后c1.php返回结果,进入浏览器事件队列开始执行,3秒后c3.php返回,进入浏览器事件队列开始执行
那么是不是说一定是这个执行顺序呢,看看下面的情况
<script src="c5.php"></script> <script> var t = document.createElement("script"); t.src="c1.php"; document.head.appendChild(t); </script> <script src="c3.php"></script>
这个结果是
5555555
3333333
11111111
为什么是这样的结果呢,其实是因为Chrome有一种预加载机制,就是浏览器会先便利整个html文本,找到其中的资源链接标记,发送http请求,所以一上来发现了c5.php和c3.php的标记,注意此时还没有c1.php的标记。所以3秒后c3.php返回结果,等待执行,因为前面的c5.php还没有执行以及后面的内嵌脚本也没有执行,所以没有轮到执行,5秒后c5.php返回结果进入浏览器事件队列开始执行,打印555555然后执行异步加载c1.php,发送异步请求,然后c3.php的结果进入浏览器事件队列开始执行,打印333333然后第6秒c1.php返回结果打印111111所以,实际上是浏览器执行是按照同步顺序执行,但是请求资源却有优化,是在页面解析第一开始就请求资源的。