<script>标签的加载解析执行

转自原文 <script>标签的加载解析执行

 

看了很多网上的文章,都是大同小异。总结一下。内部原理还没有搞清楚,有机会再学习。

一、<script>标签的加载解析执行顺序

html页面中的<script>标签中的内容(直接写入或者引用外部文件都一样)是以顺序加载执行的,每个<script>标记内容可以当成一个独立的块,同步的情况下一个块加载解析然后执行完后才加载下一块。当然这时也会阻塞其他页面元素的加载。所以网上说的变量调用:

<script type="text/javascript">//<![CDATA[

alert(tmp); //输出 undefined

var tmp = '111';

alert(tmp); //输出 111

//]]>

</script>

还有函数调用:

<script type="text/javascript">//<![CDATA[

test(); //浏览器报错

//]]>

</script>

<script type="text/javascript">//<![CDATA[

test(); //输出 fun!

function test(){alert('fun!');}

//]]>

</script>

其实很简单,对于变量,在一个作用域中在变量声明前面使用变量,本来就是undifined(解析过程中已经知道有这个变量, 但没赋值,等到执行才赋值)。对于函数,同一块中可以,因为解析的时候已经知道有那个函数了,但是分在不同块中,当test 调用时,下面声明test函数的内容根本还没被加载进来,所以调用出错。

二、document.write ()问题

本来这样不就挺好吗。但是来个document.write就坑爹了。先摘一段网上的话::“输出写入到脚本文档所在的位置,浏览器解析完documemt.write()所在文档内容后,继续解析document.write()输出的内容,然后在继续解析HTML文档”。

测试过,在一个<script>标记中通过document.write()输出的内容会依次插到该标记的后面(动态加载)。但插入内容没有解析和执行, 解析执行还是按文档顺序下来,等到执行完documemt.write()所在的script标记的内容后再解析执行。但是这仅限于document.write 方式没有写入可引用的外部文件并且引入文件内不包含document.write时的情况。

关于引入外部文件与外部文件包含document.write参考自http://w3help.org/zh-cn/causes/BX9014

例子见参考,内容大概就是:第一当document.write方式引入的外部文件里面包含document.write写入流,IE 是在当前 SCRIPT 标记内所有的 document.write 向文档中输出内容完成后,再处理以 document.write 方式引入的 JS 文件内的 document.write 写入流。对于其他浏览器,则根据代码执行顺序依次处理 document.write 方式写入的内容(但测试过,外部文件中除document.write外的内容对于ie和firefox一样,是等到当前 SCRIPT 标记执行结束后才执行的)。第二,当使用 document.write 方式写入可引用的外部JavaScript 内容后,非 IE Opera 浏览器并不会立即更新 DOM 树。

对于第二点,我觉得恰好可以解释网上所说的一个问题(没有debug,原因最后说明),问题如下


<script type="text/javascript">//<![CDATA[
        document.write('<script type="text/javascript" src="test.js"><\/script>');       
   document.write('<script type="text/javascript">');       
    document.write('alert("222");')       
    document.write('alert("变量保存值" + tmpStr);');       
    document.write('<\/script>');        //]]>
</script>
    <script type="text/javascript">//<![CDATA[
        alert("333");        //]]>
 </script>

test.js的内容是:

    var tmpStr = '111';        alert(tmpStr);
  • 在Firefox和Opera中的弹出值的顺序是:111、222、变量保存值111、333

  • 在IE中弹出值的顺序是:222、111、333, 同时浏览器报错:tmpStr未定义

原因可能是IE在document.write时,并未等待加载SRC中的Javascript代码完毕后,才执行下一行,所以导致222先弹出,并且执行到document.write(‘document.write(“变量保存值” + tmpStr)’)调用tmpStr时,tmpStr并未定义,从而报错。


但是我觉得原因不是这个,原因应该就是其他浏览器没有立即更新dom树。IE会在document.write('<script type="text/javascript" src="test.js"><\/script>')后更新dom树,此时dom树中引用test文件的<script>节点已存在,后续插入的<script>节点都会被插入在正在执行的<script>的后面,也就是引入test文件的<script>节点的前面。所以执行alert时test内容还没执行。而其他浏览器是当<script>的内容执行完毕后再更新dom树,所以document.write写入的内容是以顺序添加到包含他们的<script>后面的。当然这只是我个人理解,如果错误还请看到的人指出。

最后一个问题,对于使用document.write时出现的firefox和IE间的处理不一致,当我firefox用debug设断点调试(一步一步跳)时竟然变得跟IE一致了。像上面那个例子firefox断点调试时竟然tempStr也是notdefined,引入的文件没有跳进去。js我也是学得不久有懂的请赐教。

花了一天还没搞明白,真不知道去抠这些问题有没有价值,觉得还是少用document.write吧。

 

 

posted @ 2017-09-13 17:55  wenglabs  阅读(882)  评论(0编辑  收藏  举报