网页的加载和执行顺序?

我做过一些基于web的项目,但我没有过多考虑一个普通网页的加载和执行顺序。但现在我需要知道细节。很难从谷歌或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>h2{font-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>

下面是我的问题:

  1. 这个页面是如何加载的?
  2. 装载的顺序是什么?
  3. JS代码什么时候执行?(内联和外部)
  4. CSS什么时候执行(应用)?
  5. 什么时候$(document)。准备好被处决了吗?
  6. 会下载abc.jpg吗?还是直接下载kkk.png?

我有以下认识:

  1. 浏览器首先加载html (DOM)。
  2. 浏览器开始逐行从上到下加载外部资源。
  3. 如果遇到<script>,加载将被阻塞,等待JS文件被加载和执行,然后继续。
  4. 其他资源(CSS/图像)并行加载并在需要时执行(如CSS)。

或者是这样的:

浏览器解析html (DOM)并以数组或类似堆栈的结构获取外部资源。html加载后,浏览器开始并行加载结构中的外部资源并执行,直到所有资源都加载完毕。然后DOM将根据用户的行为(取决于JS)进行相应的更改。

有人能详细解释一下当你得到一个html页面的响应时发生了什么吗?这在不同的浏览器中是否有所不同?有关于这个问题的参考资料吗?

谢谢。

编辑:

我用Firebug在Firefox中做了一个实验。如下图所示: alt text

167704 次浏览

编辑:现在是2022年。如果你对网页的加载和执行以及浏览器如何工作的详细内容感兴趣,你应该查看https://browser.engineering/(在https://github.com/browserengineering/book上开源)


根据你们的样品,

<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>h2{font-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>

执行流程大致如下:

  1. HTML文档被下载
  2. HTML文档的解析开始
  3. HTML解析达到<script src="jquery.js" ...
  4. jquery.js被下载并解析
  5. HTML解析达到<script src="abc.js" ...
  6. abc.js被下载、解析并运行
  7. HTML解析达到<link href="abc.css" ...
  8. abc.css被下载并解析
  9. HTML解析达到<style>...</style>
  10. 内部CSS规则被解析和定义
  11. HTML解析达到<script>...</script>
  12. 内部Javascript被解析并运行
  13. HTML解析达到<img src="abc.jpg" ...
  14. abc.jpg被下载并显示
  15. HTML解析达到<script src="kkk.js" ...
  16. kkk.js被下载、解析并运行
  17. HTML文档解析结束

请注意,由于浏览器的行为,下载可能是异步的和非阻塞的。例如,在Firefox中有这样的设置,它限制每个域同时请求的数量。

另外,根据组件是否已经缓存,在不久的将来可能不会再次请求该组件。如果组件已经被缓存,组件将从缓存中加载,而不是实际的URL。

当解析结束,文档准备好并加载时,事件onload将被触发。因此,当onload被触发时,将运行$("#img").attr("src","kkk.png");。所以:

  1. 文档准备就绪,onload启动。
  2. Javascript执行命中$("#img").attr("src", "kkk.png");
  3. kkk.png被下载并加载到#img

$(document).ready()事件实际上是在加载并准备好所有页面组件时触发的事件。阅读更多关于它:http://docs.jquery.com/Tutorials: Introducing_ $(文档)时()

编辑-这部分详细阐述了“是否平行”部分:

默认情况下,根据我目前的理解,浏览器通常以3种方式运行每个页面:HTML解析器、Javascript/DOM和CSS。

HTML解析器负责解析和解释标记语言,因此必须能够调用其他两个组件。

例如,当解析器遇到这一行时:

<a href="#" onclick="alert('test');return false;" style="font-weight:bold">a hypertext link</a>

解析器将进行3次调用,两次调用Javascript,一次调用CSS。首先,解析器将创建这个元素并在DOM名称空间中注册它,以及与该元素相关的所有属性。其次,解析器将调用onclick事件绑定到这个特定的元素。最后,它将再次调用CSS线程,将CSS样式应用于这个特定的元素。

执行是自上而下和单线程的。Javascript看起来是多线程的,但实际上它是单线程的。这就是为什么当加载外部javascript文件时,主HTML页面的解析被挂起。

然而,CSS文件可以同时下载,因为CSS规则总是被应用-这意味着元素总是用定义的最新CSS规则重新绘制-从而使它不阻塞。

一个元素只有在被解析后才在DOM中可用。因此,在处理特定元素时,脚本总是放置在window 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>

如果你问这个问题是因为你想要加速你的网站,检查雅虎的页面加快网站速度的最佳实践。它有很多加速你的网站的最佳实践。

1)下载HTML。

2) HTML是逐步解析的。当到达对某个资产的请求时,浏览器将尝试下载该资产。大多数HTTP服务器和浏览器的默认配置是只并行处理两个请求。IE可以重新配置下载无限数量的资产并行。Steve Souders已经能够在IE上并行下载超过100个请求。唯一的例外是脚本请求会阻塞IE中的并行资产请求。这就是为什么强烈建议将所有JavaScript放在外部JavaScript文件中,并将请求放在HTML中的结束主体标记之前。

3)一旦HTML被解析,DOM就被渲染。在几乎所有的用户代理中,CSS与DOM的呈现是并行呈现的。因此,强烈建议将所有CSS代码放在外部CSS文件中,这些文件在<head></head>文档的一部分。否则,页面呈现到DOM中CSS请求位置的出现位置,然后从头开始呈现。

4)只有在DOM完全呈现并且页面中所有资产的请求都被解析或超时之后,JavaScript才会从onload事件执行。如果没有从资产请求接收到HTTP响应,IE7(我不确定是否有IE8)不会快速超时资产。这意味着JavaScript内联到页面请求的资产,即写入HTML标记的JavaScript,不包含在函数中,可以阻止onload事件的执行数小时。如果页面中存在这样的内联代码,并且由于名称空间冲突导致代码崩溃而无法执行,则会触发此问题。

在上述步骤中,最消耗CPU的是DOM/CSS的解析。如果你想让你的页面处理得更快,那么通过消除冗余指令和将CSS指令整合到尽可能少的元素引用中来编写高效的CSS。减少DOM树中的节点数量也会产生更快的呈现速度。

请记住,您从HTML甚至从CSS/JavaScript资产请求的每个资产都是使用单独的HTTP头请求的。这将消耗带宽并需要处理每个请求。如果你想让你的页面加载尽可能快,那么减少HTTP请求的数量和减少HTML的大小。仅仅从HTML中获得平均180k的页面重量对用户体验没有任何好处。许多开发人员都赞同这样的谬说:用户在6纳秒内就决定了页面内容的质量,然后从服务器上清除DNS查询,如果不满意就烧毁他的计算机,所以他们提供了25万HTML的最漂亮的页面。保持你的HTML短小精悍,这样用户可以更快地加载你的页面。没有什么比快速响应的网页更能改善用户体验了。

在Firefox中打开页面并获取HTTPFox插件。它会告诉你所需要的一切。

在archivism .incuito上找到了这个:

http://archivist.incutio.com/viewlist/css-discuss/76444

当你第一次请求一个页面时,你的 浏览器发送一个GET请求到 服务器,它将HTML返回到 浏览器。然后浏览器启动 解析页面(可能在所有之前)

当它找到对象的引用时,

外部实体,如CSS文件,或 图像文件,脚本文件,Flash 文件,或任何外部的 页面(要么在同一页上 服务器/域与否),它准备 进一步GET请求 资源。< / p >

但是HTTP标准指定 浏览器不应该创造更多 的两个并发请求 相同的域。所以它把每个请求 到队列中的特定域,以及 当每个实体返回时,它就开始了 下一个排队的人 域。< / p >

实体变为 返回的值取决于它的大小 当前加载服务器 体验,和活动 每一台机器之间 运行浏览器和 服务器。这些机器的列表 原则上可以不同吗 每一个请求,只要一个 这张照片可能会从美国传到我身上 在大西洋上的英国,而 来自同一服务器的另一个输出 途经太平洋、亚洲和欧洲, 这需要更长的时间。你可能会得到a 序列如下,其中a 页面有引用(按此顺序) 3个脚本文件,5个图像 文件,所有不同的大小:

  1. 获取script1和script2;对script3和images1-5进行队列请求。
  2. script2到达(它小于script1): GET script3,队列 李images1-5。< / >
  3. script1到来;GET image1, queue images2-5。
  4. image1到达,GET image2,排队images3-5。
  5. script3由于网络问题无法到达-重新GET script3 李(自动重试)。< / >
  6. Image2到了,script3还没到;GET image3, queue images4-5。
  7. 图像3到达;GET image4, queue image5, script3仍在路上。
  8. image4到达,GET image5;
  9. image5到来。
  10. script3到来。
简而言之:任何旧订单,取决于 服务器在做什么,什么 互联网上的其他人在做什么,还有 是否有错误 并且必须重新获取。这可能 这样做有点奇怪 事情,但它真的会 对互联网来说是不可能的(不是 只要WWW),任何学位都可以工作 如果不是这样做的话 方式。< / p > 同样,浏览器的内部队列 可能无法按顺序获取实体 它们出现在页面上,但不是

(哦,别忘了缓存,两者都在 浏览器和缓存代理 网络服务提供商用来减轻网络上的负载 网络。)< / p >

Dynatrace AJAX版显示了页面加载、解析和执行的确切顺序。

AFAIK,浏览器(至少Firefox)在解析每个资源时立即请求它。如果它遇到一个img标记,它将在img标记解析完成后立即请求该图像。这甚至可以在它接收到HTML文档的全部之前……也就是说,当这种情况发生时,它可能还在下载HTML文档。

对于Firefox,有一些浏览器队列可以应用,这取决于它们在about:config中的设置方式。例如,它不会尝试一次从同一服务器下载超过8个文件…额外的请求将被排队。我认为有每个域的限制,每个代理的限制,以及其他东西,这些都在Mozilla网站上有文档,可以在about:config中设置。我在某处读到IE没有这样的限制。

jQuery ready事件在主HTML文档被下载并被DOM解析后立即触发。然后,一旦所有链接的资源(CSS、图像等)都下载并解析完毕,load事件就会触发。这在jQuery文档中有明确说明。

如果您想控制所有加载的顺序,我相信最可靠的方法是通过JavaScript。

选择的答案看起来不适用于现代浏览器,至少在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>h2{font-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资源不包括在内)。