[html] 第22天 js放在html的<body>和<head>有什么区别?
Opened this issue · 14 comments
js放在html的<body>
和<head>
有什么区别?
浏览器解析html从上往下执行,放在head先执行js了,会造成dom树还没有生成就执行js。
head标签准确来说,是对html文档的一种配置
- 放在head 比放在body先解析,放在head里在被调用时才执行,body里加载的时候执行
js 放在 <head>
中,如果不添加 async
或者 defer
时,当浏览器遇到 script
时,会阻塞 DOM 树的构建,进而影响页面的加载。当 js 文件较多时,页面白屏的时间也会变长。
在这个过程中,如果解析器遇到了一个脚本(script),它就会停下来,并且执行这个脚本,然后才会继续解析 HTML。如果遇到了一个引用外部资源的脚本(script),它就必须停下来等待这个脚本资源的下载,而这个行为会导致一个或者多个的网络往返,并且会延迟页面的首次渲染时间。
把 js 放到 <body>
里(一般在 </body>
的上面)时,由于 DOM 时顺序解析的,因此 js 不会阻塞 DOM 的解析。对于必须要在 DOM 解析前就要加载的 js,我们需要放在 <head>
中。
参考文章:
该把 JS 文件放在 HTML 文档的那个位置
在浏览器解析HTML中的时候,如果在head标签中遇到了script标签并且是同步执行的,那么就会影响文档的加载,如果引入的过多的同步脚本文件
那么加载会变得非常怪异且卡顿;但是放在body中,根据script标签,从上到下的解析顺序,它不会对html进行阻塞;
那么在一般业务中我们如何做呢?一般情况下是在网站中,同步在head加载的脚本通常是业务必须的,比如说我要注册一个window对象,或者用document.write写入一些内容,或者是业务需求,我们可以用head来做加载,
就是意味着没有这个脚本,下面的文档走不下去;
那么我们也可以在头部给script标签加入async的属性,表示它是异步加载的脚本,不会对html进行阻塞,这也是大部分网站的做法;
除了上面的情况我们都需要把js引入到底部或者body中合适的位置,比如说我的jq从那个html代码进行了使用,那么就在它之前均可;
js 放在
<head>
中,如果不添加async
或者defer
时,当浏览器遇到script
时,会阻塞 DOM 树的构建,进而影响页面的加载。当 js 文件较多时,页面白屏的时间也会变长。在这个过程中,如果解析器遇到了一个脚本(script),它就会停下来,并且执行这个脚本,然后才会继续解析 HTML。如果遇到了一个引用外部资源的脚本(script),它就必须停下来等待这个脚本资源的下载,而这个行为会导致一个或者多个的网络往返,并且会延迟页面的首次渲染时间。
把 js 放到
<body>
里(一般在</body>
的上面)时,由于 DOM 时顺序解析的,因此 js 不会阻塞 DOM 的解析。对于必须要在 DOM 解析前就要加载的 js,我们需要放在<head>
中。参考文章:
该把 JS 文件放在 HTML 文档的那个位置
上面很多都是纸上谈兵,这个回答相对靠谱。我做一些补充。
关于这个问题,我自己写个后端延迟脚本试验过。讲清楚区别,首先要了解浏览器渲染大过程。我们老生常谈,一般浏览器渲染过程分为,html解析-->dom树构建-->渲染树构建-->渲染树布局-->渲染树呈现 这样一个过程。
在以上过程中,需要了解的是,渲染树构建和dom树构建的区别,渲染树实际上是css展示样式和dom树结合创建过程,此过程依赖css的样式。而渲染树布局依赖css的布局样式。
基于上面的论点,也就是说,页面需要展示内容的过程是依赖css,而普通js脚本的加载又是依赖css正在加载的脚本的。
接下来回到上面的问题,js放在head和放在body的区别首先要搞清楚是有没css影响,有css影响时候是在css前还是css后面。
- 没有css的情况下。
那么浏览器到渲染到script脚本时候需要等待script脚本的载入和运行。这是两个过程,两个过程都是阻塞的。
这也就导致,如果在head中放了script标签,因为html解释过程是边解析边输出(dom),此是在等待js完成后,由于上面的dom树构建部分还未完成,如果js有使用到dom的脚本,那么会报错。如果只是单纯的console.log其实是没有问题的。
放在body后,html解析到这里的时候dom树基本构建完成。js脚本加载和执行都不会有任何影响。而且这两种都页面解析是停止的。需要讨论异步情况,要关注defer和async两个属性。这里不做深究。
- 在有css情况下
浏览器的渲染中,dom树是会继续构建,但是js在css后面的时候,需要等待真正加载css完成才会执行。css过程不会阻塞页面dom树的构建,但是会阻塞渲染树的构建。此时反正body后会受延迟css的影响,不延迟不影响。defer和async默认会认为与css不相关,不受css影响。反正css前和1讨论没区别。
- html渲染是从上至下,依次构建DOM树=>渲染树,如果遇到CSS会阻止渲染树的构建,如果遇到脚本(JS)则DOM树和渲染树都会停止构建。
- 由于JS文件一般要请求接口、文件和做复杂的处理,放在body的后面可以先让HTML和CSS先渲染出来,展示界面。不至于傻傻等JS执行完,去展示一段时间的空白。
- 所以我们要把JS放到前面或者添加 async 或者 defer属性,这样不管JS如何都不会影响界面样式和结构的展示速度
浏览器解析 html
文件是从上至下的,暂且不谈论 css 文件的引入,只谈 js 文件和 html dom 标签。
说到 <script>
标签,那么它是具有两个属性的。async
异步加载 和 defer
延迟加载。
<script>
当 script
标签 放在 head
中,并且这个 script
标签只有 src
属性引入外部 js 文件的情况下,html 文件开始渲染,直到命中 script
标签,此时解析将停止,并发出一个请求获取该文件并执行。执行结束之后继续渲染 html 标签。
<script async>
使用 async
会在 html 解析期间下载文件,并在下载完成后暂停 html 的解析,执行下载的外部 js 文件。直接后继续解析 html
<script defer>
它和 async
的区别是,同样在 html 解析期间下载外部的 js 文件,但是下载完成后不会立即执行 js 脚本文件,而是等到 html 解析完成后才执行它。 即在 DOMContentLoaded
之间执行已下载的 外部 js 文件。
什么场景下使用 async
或 defer
呢?
- 如果 script 是模块化,并且不依赖于任何脚本,那么使用 async
- 如果脚本依赖于或者被另一个脚本依赖,那么使用defe
当把 script
脚本放在 body
标签内就不用解释了吧。和 <script defer>
很像不是么?
html渲染是从上至下,依次构建DOM树=>渲染树,如果遇到CSS会阻止渲染树的构建,如果遇到脚本(JS)则DOM树和渲染树都会停止构建。
由于JS文件一般要请求接口、文件和做复杂的处理,放在body的后面可以先让HTML和CSS先渲染出来,展示界面。不至于傻傻等JS执行完,去展示一段时间的空白。
所以我们要把JS放到前面或者添加 async 或者 defer属性,这样不管JS如何都不会影响界面样式和结构的展示速度
get ()
js放在head里面会阻塞dom树的加载
放在body里面不会
放在中,则无法直接获取网页中的元素,获取元素的代码需要放在window.onload中
- 在HTML body部分中的js会在页面加载的时候被执行。
- 在HTML head部分中的js会在被调用的时候才执行,但是在主页和其余部分代码之前预先装载
从JavaScript对页面下载性能方向考虑:由于脚本会阻塞其他资源的下载(如图片等)和页面渲染,直到脚本全部下载并执行完成后,页面的渲染才会继续,因此推荐将所有的<script>
标签尽可能放到<body>
标签的底部,以尽量减少对整个页面下载的影响
放在body中,会在页面加载的时候执行
放在head中,被调用的时候才执行