您的位置:首页 > Web前端 > JavaScript

把JavaScript文件放在文档的头部还是尾部

2018-03-09 16:03 537 查看
首发于:技术风暴

我们今天来聊一聊关于JavaScript文件的引入位置的问题;大家在平时的Web开发中有没有想过这样一个问题,那就是我应该在文档的头部(也就是
<head>
标签内部里面)引入所需要的JavaScript文件还是应该在尾部(也就是
</body>
之前)引入所需要的JavaScript文件呢?今天我们就来深入的探究一下这个问题。

首先我们需要了解的一点就是,在浏览器渲染页面之前,它需要通过解析
HTML
标记然后构建
DOM
树。在这个过程中,如果解析器遇到了一个脚本(
script
),它就会停下来,并且执行这个脚本,然后才会继续解析
HTML
。如果遇到了一个引用外部资源的脚本(
script
),它就必须停下来等待这个脚本资源的下载,而这个行为会导致一个或者多个的网络往返,并且会延迟页面的首次渲染时间。


还有一点是需要我们注意的,那就是外部引入的脚本(
script
)会阻塞浏览器的
并行下载
HTTP/1.1规范表明,浏览器在每个主机下并行下载的组件不超过两个(也就是说,浏览器一次只能够同时从同一个服务器加载两个脚本);如果你网站的图片是通过多个服务器提供的,那么按道理来说,你的网站可以一次并行下载多张图片。但是,当我们网站在加载脚本的时候;浏览器不会再启动任何其它的下载,即使这些组件来自不同的服务器。


看到这里,也许很多开发者都会想:既然把脚本(
script
)资源放在
head
里面是个不好的主意,并且可能会阻塞浏览器渲染页面;那我们是不是要把所有的
JavaScript
文件都放置到文档的底部呢?这个当然也是太过极端了,因为还是有一些情况需要我们在头部引用脚本的;到底是哪些情况需要我们这么做呢,下面我们来看看一些大公司的做法:



我们可以看到,这个搜索页面在头部加载了5个JavaScript文件(箭头标注的地方),其中两个JavaScript文件是内联的(
inline
),另外三个大家可以看到
script
标签上都添加了
async
属性,那这个属性是干嘛的呢?我们会在下面解释。


baidu搜索页在head中引入的JavaScript
我们可以看到,百度也在头部引入了一些JavaScript文件,这些文件引入的方式与Google的做法差不多,都在引入外部资源的
script
标签上添加了
async
属性,除了第一个JavaScript文件没有那样做。


stackoverflow首页在head中引入的JavaScript


weibo首页在head中引入的JavaScript

最后一个是facebook的首页,令我比较出乎意料的是,facebook的首页的头部引入了大量的脚本(
script
),大家可以看一下截图


facebook首页在head中引入的JavaScript


facebook首页在head中引入的JavaScript
不过基本上facebook的
script
标签上面都添加了
async
属性,下面我们先来来说一下
script
标签上面这个
async
属性的作用。

这个属性是HTML5给
script
新添加的属性,而且只适用于外部的JavaScript文件,如果在
script
标签上添加了这个属性,那么表明这个脚本资源就不再是同步加载的了,而是异步加载的,所以不会阻塞浏览器对页面的渲染。当然这个属性会存在一些兼容性问题,一些浏览器还未实现对这个属性的支持。


我们可以看到,虽然这些网站大部分的
script
标签(针对引入的外部文件)都添加了
async
属性,但是还是有一些
script
标签没有添加
async
属性,那就表示这些资源是同步加载执行的,在这里你可能会问,那这些资源为什么不使用异步加载呢?原因很大程度上是因为,这些脚本需要在浏览器渲染页面之前就执行的;比如Yahoo在Best Practices for Speeding Up Your Web Site中就指出,如果你的脚本中使用了
document.write
在页面中插入内容的话,那就不能够将这条脚本放置到文档的底部了。类似的还有weibo,weibo的
head
中也使用了一个要在页面渲染之前就执行的脚本,如下:

1234
<script type="text/javascript">    try {document.execCommand("BackgroundImageCache", false, true);        } catch (e) {}</script>
还有百度首页的
head
中也有两条需要在页面渲染之前就执行的JavaScript文件:

1234567
<script data-compress="strip">function h(obj){    obj.style.behavior='url(#default#homepag
4000
e)';   var a = obj.setHomePage('//www.baidu.com/');}</script><script>window._ASYNC_START=new Date().getTime();</script>
还有一些比如Google和Baidu他们搜索页面同步加载的那些JavaScrip文件一些是为了在页面渲染之前做一些全局的处理(比如Google)添加了全局变量
google



google搜索页面同步加载的JavaScript
还有的就是单纯的满足自己业务上的一些需求了,比如百度同步加载的那个JavaScript文件:


baidu搜索页面同步加载的JavaScript

所以说,除了上面这些情况外,其它的情况下我们的脚本资源都需要放在文档的底部;当然这里还有一些需要我们注意的问题,首先,脚本加载的顺序很重要,比如如果你的脚本需要使用
jQuery
库,那么你就应该在加载你的脚本之前先加载
jQuery
库。其次,有些脚本是需要等到某些元素加载完成之后才可以执行的,那么你可以将你的脚本紧挨在那个元素的后面;还有一些元素是通过脚本动态创建的,所以它们也需要放在合适的位置。比如微博的:


weibo通过脚本动态创建的元素

如果使用过一些框架的脚手架你就会发现,这些框架打包后的那个
index.html
里面引入的外部JavaScript资源都是放在文档的底部的,并且它们也是按照顺序来的,
vendor.js
文件(项目使用的框架,库打包形成的文件)先引入,然后才是
app.js
文件(我们写的代码文件打包形成的),这就说明了引入脚本文件的顺序也是很重要的。

到现在为止,我们已经讨论了很多关于把JavaScript文件放在文档的头部还是尾部的原因,那么下面我们可以总结出一些加载JavaScript文件的最佳实践;

对于必须要在DOM加载之前运行的JavaScript脚本,我们需要把这些脚本放置在页面的
head
中,而不是通过外部引用的方式,因为外部的引用增加了网络的请求次数;并且我们要确保内敛的这些
JavaScript
脚本是很小的,最好是压缩过的,并且执行的速度很快,不会造成浏览器渲染的阻塞。


对于支持使用
script
标签的
async
defer
属性的浏览器,我们可以使用这两个属性;其中需要注意的点就是,
async
表示的意思是异步加载JavaScript文件,它的下载过程可以在HTML的解析过程中进行,加载完成之后立即执行这个文件的代码,执行文件代码的过程中会阻塞HTML的解析,它不保证文件加载的顺序。
defer
表示的意思是在HTML文档解析之后在执行加载完成的JavaScript文件,JavaScript文件的下载过程可以在HTML的解析过程中进行,它是按照
script
标签的先后顺序来加载文件的。更多详细的解释可以参考async vs defer attributes


到这里为止,整篇文章就算是结束了,如果你还想进一步的了解关于JavaScript文件加载的一些知识,可以看看这篇文章

参考的一些资料:

Remove Render-Blocking JavaScript

Put Scripts at the Bottom

Best Practice: Where to include your script tags

Script Element

execCommand

What is difference between using JavaScript in head and body?

Where To Include JavaScript Files In A Document

Should I always put my JavaScript file in the head tag of my HTML file so that the code is loaded at the start?

Why put JavaScript in head

Deep dive into the murky waters of script loading

Asynchronous and deferred JavaScript execution explained

本作品保留所有权利。未获得许可前,不允许他人复制、发行、展览和表演作品。不允许他人基于该作品创作演绎作品。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: