HTML文档中标签位置问题

感谢

本笔记来自这两位博主文章
1、<script>在HTML文档中位置
2、关于<Script>标签在html页面放置位置


一、HTML文档解释方式

  • 按照HTML文档中顺序依次从上到下解释
  • 解释过程中遇到<link>就会异步的下载css然后继续向下解释
  • 遇到<img>就会异步的下载图片,然后继续向下解释
  • 遇到<script>会立刻停止继续向下解释,然后开始同步请求js文件,然后逐句执行JS文件中的代码,直到代码都执行完,然后再回去解释HTML

二、Script标签的位置

一般script标签会被放在头部或尾部。头部就是<head></head>里面,尾部一般指<body></body>里,但也有放在闭合标签之后的。

1.script标签放置在head标签内部时:

将script放在里,浏览器解析HTML,发现script标签时,会先下载完所有这些script,再往下解析其他的HTML。讨厌的是浏览器在下载JS时,是不能多个JS并发一起下载的。不管JS是不来来自同一个host,浏览器最多只能同时下载两个JS,且浏览器下载JS时,就block掉解析其他HTML的工作。将script放在头部,会让网页内容呈现滞后,导致用户感觉到卡。

2.script标签放置在body标签内部时:

将script放在尾部的缺点,是浏览器只能先解析完整个HTML页面,再下载JS。而对于一些高度依赖于JS的网页,就会显得慢了。所以将script放在尾部也不是最优解,最优解是一边解析页面,一边下载JS。


3.script标签放置在body标签之后时:

首先声明。这在之后插入其他元素,从HTML 2.0起就是不合标准的。按照HTML5标准中的HTML语法规则,如果在</body>后再出现<script>或任何元素的开始标签,都是parse> error,浏览器会忽略之前的,即视作仍旧在body内。所以实际效果和写在之前是没有区别的。这种写法虽然也能work,但是并没有带来任何额外好处,实际上出现这样的写法很可能是误解了“将script放在页面最末端”的教条。所以还是不要这样写为好。

因为在body以外写script也可能存在其他异常嘛。有什么理由能让开发者推断出后者会更安全呢?实际上在没有充分测试的前提下,如果要进行推断,那么可以推断出后者的风险更大。

第一,这是不合标准的行为,而且从有HTML标准以来都是不合标准的,因此浏览器实现不一致或者在这种情况下有bug的风险显然更大。

第二,虽然将<script>写在之后,但最终的DOM树里,<script>元素还是会成为body的子节点,这一点很容易在firebug等调试器里验证。既然如此,如果将<script>写在</body>之前会有问题,你又如何保证写在之后(并在DOM里又变成了和写在之前一样的结构)就没有问题?

那最优解的一边解析页面一边下载JS应该怎样实现呢?

我们<script>标签这里面有两个属性(async和defer),现在80%的浏览器都可以识别他们,这两个属性能让浏览器做到一边下载JS(还是只能同时下载两个JS),一边解析HTML。他的优点不是增加JS的并发下载数量,而是做到下载时不block解析HTML。

<script type="text/javascript" src="path/to/script1.js" async></script>  
<script type="text/javascript" src="path/to/script2.js" async></script>  

我们同时引入两条外部js文件时:

sync属性能保证script会异步执行,只要下载完就执行,这会导致script2.js可能先于script1.js执行(如果script2.js比较大,下载慢)。
defer属性就能保证script有序执行,script1.js先执行,script2.js后执行。

三:浏览器工作流程:

  1. 解析HTML文档生成DOM树
  2. 解析CSS生成CSSOM树
  3. CSSOM树和DOM树结合形成Rendering Tree
  4. Layout
  5. 渲染

那么问题来了,rendering tree生成完计算完位置才会渲染页面,那么<script>标签不论放在哪里怎么会对浏览器渲染有影响,毕竟<script>也是DOM树的一部分啊?

Q:使用defer属性可以理解为将DOM树生成完毕Render树生成完毕Layout和渲染都做完再执行JS吗?似乎看起来安全性也比较高,因为毕竟所有的DOM都挂载好了不会出现getElementBy为空了**

实际情况

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
</head>
<body>
<div>
    加载前
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mustache.js/2.3.0/mustache.min.js"></script>
<div id="list">
    加载后
</div>
</body>
</html>

然后调整Chrome devTool的network为slow 3G
发现页面出现的效果是,首先出现加载前过了一段时间出现了加载后

这样的现象确实验证了大红书所说无误,那么该怎么解释render tree的问题呢?
解答
先说结果吧:
JS 会阻塞 DOM 解析,也就是说JS会阻塞DOM TREE的生成

因此如果你将<script>放在<head>中,会阻塞解析body的DOM和生成可见DOM TREE的过程

浏览器遇到 <script>且没有defer或async属性的 标签时,会触发页面渲染(前提:CSSOM TREE构建完毕)

因此解释了刚刚的demo(demo中没有css文件)中,浏览器将script标签之前的内容都展示了出来
css会阻塞render Tree生成
即 css会阻塞页面Layout和渲染

解释:

css文件不会阻塞DOM Tree生成过程
Render Tree必须等待DOM Tree和CSSOM Tree创建完
css文件阻塞了页面渲染
之前提到浏览器遇到<script>会渲染一次页面,如果在Head中遇到<script>同样也会渲染,虽然没有DOM树,但是如果之前有css那么就必须要等待CSSOM TRee生成之后才能渲染,因此css同样也会阻塞JS的执行

理解:

这样是很好解释的,毕竟css的出现一般都会影响到页面的Layout以及渲染,所以等待css执行完毕再渲染页面这样耗损也最少

JS会阻塞DOM Tree的完整创建

解释

  • 如果JS放在Head中,遇到<script> 渲染不出任何东西,然后中断解析body创建DOM Tree,然后运行JS,导致首屏空白时间变长
  • 如果JS放在Body的中间,遇到<script> 渲染出JS之前的DOM TREE内容,首屏空白时间不会受影响,但是会延迟完整DOMTREE的展示
  • 如果JS放在Body的最后,遇到<script> 渲染出JS之前的创建好的整个DOM
    TREE,首屏空白时间不会受影响,并且可以渲染出完整的body中内容

理解:

浏览器并不知道脚本的内容是什么,如果先行解析下面的DOM,万一脚本内全删了后面的DOM,浏览器就白干活了。浏览器无法预估JS里面的内容,那就干脆全部停住,等脚本执行完再干活就好了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值