为什么脚本在正文标签的末尾
Why scripts at the end of body tag
我知道这个问题已经问过很多次了,但是我一直没有找到答案。那么,为什么建议在body标签的末尾包含脚本以获得更好的呈现呢?
来自Udacity课程https://www.udacity.com/course/ud884 - DOM和CSSOM准备好后开始渲染。JS是HTML解析阻塞,任何脚本在CSSOM准备好后启动。
所以如果我们得到:
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>CRP</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<!-- content -->
<script src="script.js"></script>
</body>
</html>
CRP值为:
CSSOM ready > JS execute > DOM ready > Rendering
如果脚本在头部:
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>CRP</title>
<link rel="stylesheet" href="styles.css">
<script src="script.js"></script>
</head>
<body>
<!-- content -->
</body>
</html>
CRP是相同的:
CSSOM ready > JS execute > DOM ready > Rendering
这个问题只是关于"同步"脚本(没有async/defer属性)。
脚本历来会阻止额外的资源被更快地下载。通过将它们放在底部,您的样式、内容和媒体可以更快地下载,从而使感觉性能得到改善。
进一步阅读:async
和defer
属性。
在我看来,这是一种过时的做法。最近,JavaScript更倾向于将任何需要DOM呈现的代码分离到"DOMContentLoaded"事件侦听器中。这并不一定是所有逻辑;很多代码可以在不访问完整DOM的情况下进行初始化。
这确实会导致一小段时间只检索脚本文件,而不检索其他文件(例如,图像)。这个小窗口可以通过添加async
属性跳过,但即使没有它,我建议在头部放置脚本标签,以便浏览器知道尽快加载它们,而不是保存它们(以及任何未来的js发起的请求)。
最好的做法是将JavaScript标签放在结束标记,而不是在HTML的部分。
这样做的原因是HTML是从上到下加载的。头首先加载,然后是主体,然后是主体内的所有内容。如果我们把我们的JavaScript链接放在标题部分,整个JavaScript文件将在加载任何HTML之前加载,这可能会导致一些错误问题。
1。如果您的JavaScript中有代码,可以在JavaScript文件加载时,实际上不会有任何HTML元素它还没有影响到,所以看起来好像JavaScript代码不工作,您可能会得到错误。2.如果您有很多JavaScript,它会明显减慢页面的加载速度因为它在加载任何超文本标记语言当您将JavaScript链接放在HTML的底部时正文中,它让HTML有时间在任何JavaScript之前加载加载,可以防止错误,并加快网站的响应时间。
还有一件事:虽然最好在最后包含Javascript把你的Javascript放到你的HTML并不总是导致错误。在使用jQuery时,通常会把你所有的代码放在一个"文档准备"中。功能:
$("document"时(函数(){//你的代码在这里});
这个函数基本上是说,不要运行里面的任何代码,直到文档已准备好,或者已完全加载。这将防止任何错误,但它仍然会减慢HTML的加载时间,这就是为什么最好还是在所有HTML之后包含脚本。
放置在script标签下方的图像将等待加载,直到JS脚本加载。通过在底部放置script标记,您可以首先加载图像,从而使页面加载速度更快。
我认为这取决于你的网站或应用程序。一些web应用程序是基于JavaScript。那么将它包含在页面底部就没有意义了,而是立即加载它。如果JavaScript只是向一些基于内容的页面添加了一些不太重要的特性,那么最好在最后加载它。加载时间几乎是一样的,但用户会更早看到重要的部分(在页面完成加载之前)。
这不是为了让整个网站加载更快,而是给用户一种某些网站加载更快的印象。
例如:这就是为什么基于Ajax的网站可以给人更快的印象。接口总是相同的。只有一些内容部分会改变。
这是一个非常有用的链接。对于任何给定的网页,从.html创建文档对象模型。CSS对象模型也从. CSS中创建。
我们也知道JS文件也会修改对象。当浏览器遇到标记时,在脚本运行时立即停止创建DOM和CSS对象模型,因为它可以编辑所有内容。因此,如果js文件需要从树(DOM和CSS对象模型)中提取信息,它将没有足够的信息。
因此,脚本资源通常位于主体的末尾,大多数树已经被渲染过了。
不确定这是否有帮助,但是从这个资源script-tag-in-web中,内联脚本总是呈现阻塞,即使保存在body标签的末尾。
下面的内联脚本是首先渲染阻塞。在执行长for循环之前,浏览器不会在屏幕上绘制任何内容
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1" />
<link href="style.css" rel="stylesheet" />
<title>Critical Path: Script</title>
</head>
<body>
<p>Hello <span>web performance</span> students!</p>
<div><img src="awesome-photo.jpg" /></div>
<script>
let word = 0
for(let i =0; i<3045320332; i++){
word += i;
}
var span = document.getElementsByTagName('span')[0];
span.textContent = 'interactive'; // change DOM text content
span.style.display = 'inline'; // change CSSOM property
// create a new element, style it, and append it to the DOM
var loadTime = document.createElement('div');
loadTime.textContent = word + 'You loaded this page on: ' + new Date();
loadTime.style.color = 'blue';
document.body.appendChild(loadTime);
</script>
</body>
</html>
但是下面的'index.js'不是初始渲染阻塞,屏幕将被绘制,然后一旦外部'index.js'完成运行,span标签将被更新。
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1" />
<link href="style.css" rel="stylesheet" />
<title>Critical Path: Script</title>
</head>
<body>
<p>Hello <span>web performance</span> students!</p>
<div><img src="awesome-photo.jpg" /></div>
<script type="text/javascript" src="./index.js">
</script>
</body>
</html>
index.js
let word = 0
for(let i =0; i<3045320332; i++){
word += i;
}
var span = document.getElementsByTagName('span')[0];
span.textContent = 'interactive'; // change DOM text content
span.style.display = 'inline'; // change CSSOM property
// create a new element, style it, and append it to the DOM
var loadTime = document.createElement('div');
loadTime.textContent = word + 'You loaded this page on: ' + new Date();
loadTime.style.color = 'blue';
document.body.appendChild(loadTime);