网页的加载和执行顺序?
Posted
技术标签:
【中文标题】网页的加载和执行顺序?【英文标题】:Load and execution sequence of a web page? 【发布时间】:2010-12-20 04:59:02 【问题描述】:我做过一些基于web的项目,但我并没有过多考虑普通网页的加载和执行顺序。但现在我需要知道细节。很难从 Google 或 SO 中找到答案,所以我创建了这个问题。
一个示例页面是这样的:
<html>
<head>
<script src="jquery.js" type="text/javascript"></script>
<script src="abc.js" type="text/javascript">
</script>
<link rel="stylesheets" type="text/css" href="abc.css"></link>
<style>h2font-wight:bold;</style>
<script>
$(document).ready(function()
$("#img").attr("src", "kkk.png");
);
</script>
</head>
<body>
<img id="img" src="abc.jpg" style="width:400px;height:300px;"/>
<script src="kkk.js" type="text/javascript"></script>
</body>
</html>
所以这是我的问题:
-
此页面如何加载?
加载顺序是什么?
什么时候执行JS代码? (内联和外联)
CSS 何时执行(应用)?
$(document).ready 什么时候执行?
会下载 abc.jpg 吗?还是只下载 kkk.png?
我的理解如下:
-
浏览器首先加载 html (DOM)。
浏览器开始从上到下逐行加载外部资源。
如果遇到
<script>
,会阻塞加载,等待JS文件加载并执行后再继续。
其他资源(CSS/图像)并行加载并在需要时执行(如 CSS)。
还是这样的:
浏览器解析 html (DOM) 并以数组或类似堆栈的结构获取外部资源。 html加载完成后,浏览器开始并行加载结构体中的外部资源并执行,直到所有资源都加载完毕。然后根据 JS 的不同,DOM 会根据用户的行为发生变化。
谁能详细解释一下当你得到一个 html 页面的响应时会发生什么?这在不同的浏览器中会有所不同吗?关于这个问题的任何参考?
谢谢。
编辑:
我用 Firebug 在 Firefox 中做了一个实验。它显示为下图:
【问题讨论】:
Steve Souders 在这个领域做了大量的工作。 Google for steve+souders+high+performance 看看。 我不是说性能调优。我想知道细节。 通过阅读他的作品,我对“它”如何详细工作的理解增加了十倍,因此它仍然是一个有效的评论。版权不允许我在这里引用他的整本书,所以我仍然建议你查一下他的作品。 对事情发生顺序的一个很好的描述是here 挂钩***.com/q/12122369/632951 【参考方案1】:根据您的样本,
<html>
<head>
<script src="jquery.js" type="text/javascript"></script>
<script src="abc.js" type="text/javascript">
</script>
<link rel="stylesheets" type="text/css" href="abc.css"></link>
<style>h2font-wight:bold;</style>
<script>
$(document).ready(function()
$("#img").attr("src", "kkk.png");
);
</script>
</head>
<body>
<img id="img" src="abc.jpg" style="width:400px;height:300px;"/>
<script src="kkk.js" type="text/javascript"></script>
</body>
</html>
大概的执行流程如下:
-
HTML 文档被下载
开始解析 HTML 文档
HTML解析达到
<script src="jquery.js" ...
jquery.js
被下载并解析
HTML解析达到<script src="abc.js" ...
abc.js
被下载、解析并运行
HTML解析达到<link href="abc.css" ...
abc.css
被下载并解析
HTML解析达到<style>...</style>
解析和定义内部 CSS 规则
HTML解析达到<script>...</script>
内部 Javascript 被解析并运行
HTML解析达到<img src="abc.jpg" ...
abc.jpg
已下载并显示
HTML解析达到<script src="kkk.js" ...
kkk.js
被下载、解析并运行
HTML 文档解析结束
请注意,由于浏览器的行为,下载可能是异步且非阻塞的。例如,在 Firefox 中,此设置限制了每个域的同时请求数。
还取决于组件是否已经被缓存,在不久的将来请求中可能不会再次请求该组件。如果组件已被缓存,则组件将从缓存中加载,而不是从实际的 URL 中加载。
当解析结束并且文档准备好并加载时,会触发事件onload
。因此,当onload
被触发时,$("#img").attr("src","kkk.png");
就会运行。所以:
-
文档已准备就绪,已触发 onload。
Javascript 执行命中
$("#img").attr("src", "kkk.png");
kkk.png
已下载并加载到 #img
$(document).ready()
事件实际上是所有页面组件都加载并准备就绪时触发的事件。阅读更多信息:http://docs.jquery.com/Tutorials:Introducing_$(document).ready()
编辑 - 这部分详细说明了并行或非并行部分:
默认情况下,根据我目前的理解,浏览器通常以 3 种方式运行每个页面:HTML 解析器、Javascript/DOM 和 CSS。
HTML 解析器负责解析和解释标记语言,因此必须能够调用其他 2 个组件。
例如当解析器遇到这一行时:
<a href="#" onclick="alert('test');return false;" style="font-weight:bold">a hypertext link</a>
解析器将进行 3 次调用,其中 2 次调用 Javascript,1 次调用 CSS。首先,解析器将创建该元素并将其连同与该元素相关的所有属性一起注册到 DOM 命名空间中。其次,解析器将调用以将 onclick 事件绑定到此特定元素。最后,它会再次调用 CSS 线程以将 CSS 样式应用于此特定元素。
执行是自上而下和单线程的。 Javascript 可能看起来是多线程的,但事实是 Javascript 是单线程的。这就是为什么在加载外部 javascript 文件时,主 HTML 页面的解析被暂停的原因。
但是,CSS 文件可以同时下载,因为始终应用 CSS 规则 - 意思是说元素始终使用定义的最新 CSS 规则重新绘制 - 从而使其畅通无阻。
元素只有在被解析后才会在 DOM 中可用。因此,当使用特定元素时,脚本总是放置在窗口 onload 事件之后或之内。
这样的脚本会导致错误(在 jQuery 上):
<script type="text/javascript">/* <![CDATA[ */
alert($("#mydiv").html());
/* ]]> */</script>
<div id="mydiv">Hello World</div>
因为在解析脚本时,#mydiv
元素仍未定义。相反,这会起作用:
<div id="mydiv">Hello World</div>
<script type="text/javascript">/* <![CDATA[ */
alert($("#mydiv").html());
/* ]]> */</script>
或
<script type="text/javascript">/* <![CDATA[ */
$(window).ready(function()
alert($("#mydiv").html());
);
/* ]]> */</script>
<div id="mydiv">Hello World</div>
【讨论】:
谢谢。但是你提到由于浏览器的行为,下载可能是异步的和非阻塞的,那么什么样的组件可以异步下载(以FF为例)?<script>
会阻止其他组件,对吗?关于每个浏览器的规范的任何参考?
$(document).ready() 在 DOM 完成时触发,而不是在加载所有页面组件时触发
@Pierre 的页面组件是指 DOM -> DOM 中的任何组件。
只是为了澄清...常规 window.onload 发生在 #17 之后...那么 jquery 的 $(document).ready() 的代码在什么时候运行? #12?但是 DOM 本身是在 #1 加载的,对吗?
如果在 标签中,如果我们添加一个 在 和 【参考方案2】:
1) 下载 HTML。
2) HTML 被逐步解析。当达到对资产的请求时,浏览器将尝试下载资产。大多数 HTTP 服务器和大多数浏览器的默认配置是仅并行处理两个请求。可以重新配置 IE 以并行下载无限数量的资产。 Steve Souders 已经能够在 IE 上并行下载 100 多个请求。例外是脚本请求会阻止 IE 中的并行资产请求。这就是为什么强烈建议将所有 JavaScript 放在外部 JavaScript 文件中并将请求放在 HTML 中的结束 body 标记之前的原因。
3) 一旦 HTML 被解析,DOM 就会被渲染。在几乎所有的用户代理中,CSS 的渲染与 DOM 的渲染是并行的。因此,强烈建议将所有 CSS 代码放入文档的
部分中要求尽可能高的外部 CSS 文件中。否则页面会渲染到 DOM 中出现 CSS 请求位置,然后从顶部重新开始渲染。4) 只有在 DOM 完全呈现并且对页面中所有资产的请求都已解决或超时后,JavaScript 才会从 onload 事件中执行。 IE7,我不确定 IE8,如果没有从资产请求中收到 HTTP 响应,则不会快速超时资产。这意味着页面内嵌的 JavaScript 请求的资产,即写入 HTML 标记中的 JavaScript,不包含在函数中,可以阻止 onload 事件的执行数小时。如果页面中存在此类内联代码,并且由于命名空间冲突导致代码崩溃而无法执行,则会触发此问题。
在上述步骤中,最耗费 CPU 的步骤是解析 DOM/CSS。如果您希望更快地处理您的页面,请通过消除冗余指令并将 CSS 指令整合到尽可能少的元素引用中来编写高效的 CSS。减少 DOM 树中的节点数也会产生更快的渲染。
请记住,您从 HTML 甚至是 CSS/JavaScript 资产请求的每个资产都使用单独的 HTTP 标头进行请求。这会消耗带宽并且需要对每个请求进行处理。如果您想让页面加载速度尽可能快,请减少 HTTP 请求的数量并减小 HTML 的大小。仅通过 HTML 平均页面重量为 180k,您并没有给您的用户体验带来任何好处。许多开发人员都认为用户会在 6 纳秒内确定页面上内容的质量,然后从他的服务器中清除 DNS 查询,如果不满意会烧毁他的计算机,因此他们提供了最漂亮的页面250k 的 HTML。保持您的 HTML 简短而优美,以便用户可以更快地加载您的页面。没有什么比快速响应的网页更能改善用户体验了。
【讨论】:
将 CSS 指令整合到尽可能少的元素引用中 听起来很奇怪。如果我需要设置三个元素的样式,我需要准确引用三个元素。我不能参考样式十,可以吗?或详细说明【参考方案3】:在 Firefox 中打开您的页面并获取 HTTPFox 插件。它会告诉你你需要的一切。
在archivist.incuito 上找到这个:
http://archivist.incutio.com/viewlist/css-discuss/76444
当您第一次请求页面时,您的 浏览器发送 GET 请求到 服务器,它将 HTML 返回到 浏览器。然后浏览器启动 解析页面(可能在所有 已退回)。
当它找到一个引用 外部实体,例如 CSS 文件、 图像文件、脚本文件、Flash 文件或任何其他外部文件 页面(在同一 服务器/域与否),它准备 对此提出进一步的 GET 请求 资源。
然而 HTTP 标准规定 浏览器不应该做更多 超过两个并发请求 同一个域。所以它把每个请求 到队列中的特定域,以及 当每个实体返回时,它开始 队列中的下一个 域。
一个实体需要的时间 返回取决于它的大小, 加载服务器当前 体验和活动 之间的每一台机器 运行浏览器的机器和 服务器。这些机器的列表 原则上可以不同 每个请求,只要一个 图像可能会从美国传给我 在大西洋上空的英国,而 来自同一服务器的另一个出来 通过太平洋、亚洲和欧洲, 这需要更长的时间。所以你可能会得到一个 序列如下,其中 页面有(按此顺序)引用 到三个脚本文件和五个图像 文件,所有不同的大小:
获取脚本 1 和脚本 2; script3 和 images1-5 的队列请求。 script2 到达(比 script1 小):GET script3, queue 图片 1-5。 script1 到达;获取图像 1,对图像 2-5 进行排队。 image1 到达,GET image2,排队 images3-5。 由于网络问题,script3 无法到达 - 再次获取 script3 (自动重试)。 image2 到了,script3 还没到; GET image3,队列 images4-5。 图片3到了; GET image4,queue image5,script3 还在路上。 image4到达,获取image5; image5 到了。 script3 到达。
简而言之:任何旧订单,取决于 服务器在做什么,什么 互联网的其余部分正在做,并且 是否有任何错误 并且必须重新获取。这可能 似乎是一种奇怪的做事方式 事情,但从字面上看 互联网是不可能的(不是 只是万维网)与任何学位一起工作 如果不这样做,可靠性 方式。
另外,浏览器的内部队列 可能无法按顺序获取实体 它们出现在页面中 - 它不是 任何标准都要求。
(哦,别忘了缓存,两者都在 浏览器和缓存代理 ISP使用来减轻负载 网络。)
【讨论】:
【参考方案4】:如果您问这个是因为您想加快您的网站速度,请查看 Yahoo 的页面Best Practices for Speeding Up Your Web Site。它提供了许多加快网站速度的最佳实践。
【讨论】:
【参考方案5】:AFAIK,浏览器(至少是 Firefox)一解析就请求每个资源。如果遇到 img 标签,它将在 img 标签被解析后立即请求该图像。这甚至可能在它收到整个 HTML 文档之前……也就是说,当这种情况发生时,它仍然可能正在下载 HTML 文档。
对于 Firefox,存在适用的浏览器队列,具体取决于它们在 about:config 中的设置方式。例如,它不会尝试从同一台服务器一次下载超过 8 个文件……额外的请求将被排队。我认为有每个域的限制、每个代理的限制和其他东西,这些都记录在 Mozilla 网站上,可以在 about:config 中设置。我在某处读到 IE 没有这样的限制。
一旦主 HTML 文档 被下载并被解析 DOM,jQuery 就绪事件就会被触发。然后,一旦所有链接资源(CSS、图像等)都已下载并解析完毕,就会触发 load 事件。 jQuery 文档中有明确说明。
如果你想控制所有加载的顺序,我相信最可靠的方法是通过 JavaScript。
【讨论】:
【参考方案6】:Dynatrace AJAX Edition 显示页面加载、解析和执行的确切顺序。
【讨论】:
【参考方案7】:选择的答案似乎不适用于现代浏览器,至少在 Firefox 52 上。我观察到的是,加载 css、javascript 等资源的请求是在 HTML 解析器到达元素之前发出的,例如
<html>
<head>
<!-- prints the date before parsing and blocks HTMP parsering -->
<script>
console.log("start: " + (new Date()).toISOString());
for(var i=0; i<1000000000; i++) ;
</script>
<script src="jquery.js" type="text/javascript"></script>
<script src="abc.js" type="text/javascript"></script>
<link rel="stylesheets" type="text/css" href="abc.css"></link>
<style>h2font-wight:bold;</style>
<script>
$(document).ready(function()
$("#img").attr("src", "kkk.png");
);
</script>
</head>
<body>
<img id="img" src="abc.jpg" style="width:400px;height:300px;"/>
<script src="kkk.js" type="text/javascript"></script>
</body>
</html>
我发现加载css和javascript资源的请求的开始时间没有被阻止。看起来 Firefox 有一个 HTML 扫描,并在开始解析 HTML 之前识别关键资源(不包括 img 资源)。
【讨论】:
以上是关于网页的加载和执行顺序?的主要内容,如果未能解决你的问题,请参考以下文章