资讯专栏INFORMATION COLUMN

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

TerryCai / 3165人阅读

摘要:我们可以看到,百度也在头部引入了一些文件,这些文件引入的方式与的做法差不多,都在引入外部资源的标签上添加了属性,除了第一个文件没有那样做。

更好阅读体验,请访问dreamapple.me

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

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

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

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


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


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


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



不过基本上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中也使用了一个要在页面渲染之前就执行的脚本,如下:

还有百度首页的head中也有两条需要在页面渲染之前就执行的JavaScript文件:


还有一些比如Google和Baidu他们搜索页面同步加载的那些JavaScrip文件一些是为了在页面渲染之前做一些全局的处理(比如Google)添加了全局变量google


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

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

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

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

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

对于支持使用script标签的asyncdefer属性的浏览器,我们可以使用这两个属性;其中需要注意的点就是,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

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/88247.html

相关文章

  • 前端性能优化(三)——传统 JavaScript 优化误区

    摘要:二模块化误区加快加载和执行的速度,一直是前端优化的一个热点。结果文件减少,也达到了预期的效果。避免不必要的延迟。最后再根据文件的功能类型,来决定是放在页面的头部还是尾部。 注:本文是纯技术探讨文,无图无笑点,希望您喜欢 一.前言 软件行业极其缺乏前端人才这是圈内的共识了,某种程度上讲,同等水平前端的工资都要比后端高上不少,而圈内的另一项共识则是——网页是公司的脸面! 几年前,谷歌的一项...

    UsherChen 评论0 收藏0
  • task0002(一)- JavaScript数据类型及语言基础

    摘要:不过让流行起来的原因应该是是目前所有主流浏览器上唯一支持的脚本语言。经过测试,数字字符串布尔日期可以直接赋值,修改不会产生影响。再考虑对象类型为或者的情况。对于结果声明其类型。判断对象的类型是还是,结果类型更改。 转载自我的个人博客 欢迎大家批评指正 1. 第一个页面交互 这里最需要学习的老师的代码中,每一部分功能都由函数控制,没有创建一个全部变量。且最后有一个函数来控制执行代码...

    elarity 评论0 收藏0
  • 前端面试题总结——JS(持续更新中)

    摘要:在此基础上加入了回调函数,加载完之后会执行中定义的函数,所需要的数据会以参数的形式传递给该函数。通常的做法是,为它们指定回调函数。 前端面试题总结——JS(持续更新中) 1.javascript的typeof返回哪些数据类型 Object number function boolean underfind string 2.例举3种强制类型转换和2种隐式类型转换? 强制(parseIn...

    shery 评论0 收藏0
  • 从“雅虎军规”看性能优化

    摘要:避免重定向重定向用和状态码,下面是一个有状态码的头浏览器会自动跳转到域指明的。除此之外还有别的跳转方式元标签和,但如果你必须得做重定向,最好用标准的状态码,主要是为了让返回按钮能正常使用。要提高性能,优化这些响应至关重要。 showImg(https://segmentfault.com/img/bVbmMsz?w=652&h=367);一直以来,性能优化是开发的重中之中,而提及 前端...

    BlackMass 评论0 收藏0
  • 从“雅虎军规”看性能优化

    摘要:避免重定向重定向用和状态码,下面是一个有状态码的头浏览器会自动跳转到域指明的。除此之外还有别的跳转方式元标签和,但如果你必须得做重定向,最好用标准的状态码,主要是为了让返回按钮能正常使用。要提高性能,优化这些响应至关重要。 showImg(https://segmentfault.com/img/bVbmMsz?w=652&h=367);一直以来,性能优化是开发的重中之中,而提及 前端...

    Kyxy 评论0 收藏0

发表评论

0条评论

TerryCai

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<